diff --git a/src/app/dre-filial/analitico.tsx b/src/app/dre-filial/analitico.tsx index 3ca8fa1..5cdab95 100644 --- a/src/app/dre-filial/analitico.tsx +++ b/src/app/dre-filial/analitico.tsx @@ -1,50 +1,56 @@ -"use client"; +'use client'; -import * as React from "react"; -import { DataGridPremium, GridToolbar, GridColDef, GridFilterModel } from "@mui/x-data-grid-premium"; +import { Button } from '@/components/ui/button'; +import { Card, CardContent } from '@/components/ui/card'; +import { Checkbox } from '@/components/ui/checkbox'; +import { + Dialog, + DialogContent, + DialogFooter, + DialogHeader, + DialogTitle, + DialogTrigger, +} from '@/components/ui/dialog'; +import { + Drawer, + DrawerClose, + DrawerContent, + DrawerDescription, + DrawerHeader, + DrawerTitle, + DrawerTrigger, +} from '@/components/ui/drawer'; +import { Input } from '@/components/ui/input'; +import { + DataGridPremium, + GridColDef, + GridToolbar, +} from '@mui/x-data-grid-premium'; import { LicenseInfo } from '@mui/x-license-pro'; +import { + ArrowDown, + ArrowUp, + ArrowUpDown, + Download, + Maximize2, + Minimize2, + Search, + X, +} from 'lucide-react'; +import * as React from 'react'; +import * as XLSX from 'xlsx'; // Garantir que a licença seja aplicada no componente atualização de licença if (typeof window !== 'undefined') { try { - const PERPETUAL_LICENSE_KEY = 'e0d9bb8070ce0054c9d9ecb6e82cb58fTz0wLEU9MzI0NzIxNDQwMDAwMDAsUz1wcmVtaXVtLExNPXBlcnBldHVhbCxLVj0y'; + const PERPETUAL_LICENSE_KEY = + 'e0d9bb8070ce0054c9d9ecb6e82cb58fTz0wLEU9MzI0NzIxNDQwMDAwMDAsUz1wcmVtaXVtLExNPXBlcnBldHVhbCxLVj0y'; LicenseInfo.setLicenseKey(PERPETUAL_LICENSE_KEY); console.log('✅ Licença MUI X aplicada no componente Analítico'); } catch (error) { console.warn('⚠️ Erro ao aplicar licença no componente:', error); } } -import { Card, CardContent } from "@/components/ui/card"; -import { Button } from "@/components/ui/button"; -import { Input } from "@/components/ui/input"; -import { - Dialog, - DialogContent, - DialogHeader, - DialogTitle, - DialogFooter, - DialogTrigger, -} from "@/components/ui/dialog"; -import { - Select, - SelectTrigger, - SelectValue, - SelectContent, - SelectItem, -} from "@/components/ui/select"; -import { Checkbox } from "@/components/ui/checkbox"; -import { - Drawer, - DrawerClose, - DrawerContent, - DrawerDescription, - DrawerFooter, - DrawerHeader, - DrawerTitle, - DrawerTrigger, -} from "@/components/ui/drawer"; -import { Download, Filter, X, Search, ArrowUpDown, ArrowUp, ArrowDown, Maximize2, Minimize2 } from "lucide-react"; -import * as XLSX from "xlsx"; interface AnaliticoItem { codigo_grupo: string; @@ -123,8 +129,9 @@ const ExcelFilter: React.FC = ({ currentSort = null, }) => { const [isOpen, setIsOpen] = React.useState(false); - const [searchTerm, setSearchTerm] = React.useState(""); - const [selectedValues, setSelectedValues] = React.useState(currentFilter); + const [searchTerm, setSearchTerm] = React.useState(''); + const [selectedValues, setSelectedValues] = + React.useState(currentFilter); const [selectAll, setSelectAll] = React.useState(false); // Sincronizar selectedValues com currentFilter quando ele mudar @@ -137,10 +144,12 @@ const ExcelFilter: React.FC = ({ const values = filteredData .map((row) => { const value = row[column.field]; - if (value === null || value === undefined) return ""; + if (value === null || value === undefined) return ''; return String(value); }) - .filter((value, index, self) => self.indexOf(value) === index && value !== "") + .filter( + (value, index, self) => self.indexOf(value) === index && value !== '' + ) .sort(); return values; @@ -172,7 +181,9 @@ const ExcelFilter: React.FC = ({ newValues = selectedValues.filter((v) => v !== value); } setSelectedValues(newValues); - setSelectAll(newValues.length === filteredValues.length && filteredValues.length > 0); + setSelectAll( + newValues.length === filteredValues.length && filteredValues.length > 0 + ); }; const handleApply = () => { @@ -210,7 +221,7 @@ const ExcelFilter: React.FC = ({ Filtrar por "{column.headerName}" - +
{/* Opções de ordenação */}
@@ -222,8 +233,7 @@ const ExcelFilter: React.FC = ({ className="h-8 text-xs" onClick={() => handleSort('asc')} > - - A a Z + A a Z
@@ -273,13 +282,15 @@ const ExcelFilter: React.FC = ({ (Selecionar Tudo) - + {filteredValues.map((value) => (
handleValueToggle(value, checked)} + onCheckedChange={(checked: boolean) => + handleValueToggle(value, checked) + } />
- - + - - - {/* Conteúdo Principal - Versão Normal */} - {renderAnaliticoContent(false)} + {/* Conteúdo Principal - Versão Normal */} + {renderAnaliticoContent(false)} ); } - diff --git a/src/app/dre-filial/teste.tsx b/src/app/dre-filial/teste.tsx index c90a5e9..844c345 100644 --- a/src/app/dre-filial/teste.tsx +++ b/src/app/dre-filial/teste.tsx @@ -1459,13 +1459,335 @@ export default function Teste() { carregarPeriodosDisponiveis(); }; + // Função para construir dados hierárquicos completamente expandidos (para exportação) + const buildHierarchicalDataCompleta = + React.useCallback((): HierarchicalRow[] => { + const rows: HierarchicalRow[] = []; + + // Hierarquia simplificada: [grupo, conta] + // Agrupar por CODGRUPO + const gruposPorCodigo = data.reduce((acc, item) => { + const codgrupo = item.codgrupo || item.codigo_grupo || ''; + if (!codgrupo) return acc; + if (!acc[codgrupo]) { + acc[codgrupo] = []; + } + acc[codgrupo].push(item); + return acc; + }, {} as Record); + + // Calcular valores por grupo para linhas calculadas + const valoresPorGrupo: Record> = {}; + Object.keys(gruposPorCodigo).forEach((codgrupo) => { + valoresPorGrupo[codgrupo] = calcularValoresPorMes( + gruposPorCodigo[codgrupo] + ); + }); + + // Ordenar por CODGRUPO (numericamente) + const sortedGrupos = Object.entries(gruposPorCodigo).sort( + ([codA], [codB]) => { + const numA = parseInt(codA) || 0; + const numB = parseInt(codB) || 0; + if (numA !== numB) { + return numA - numB; + } + return codA.localeCompare(codB); + } + ); + + // Variáveis para armazenar valores da MARGEM BRUTA (para uso no RESULTADO LOJA) + let valoresMargemBrutaPorMes: Record | null = null; + let valoresMargemBrutaPorMesPorFilial: Record< + string, + Record + > | null = null; + let totalMargemBruta: number | null = null; + + sortedGrupos.forEach(([codgrupo, items], index) => { + // Calcular total do grupo + const totalGrupo = items.reduce( + (sum, item) => sum + parseFloat(item.valor), + 0 + ); + const valoresGrupoPorMes = calcularValoresPorMes(items); + const valoresGrupoPorMesPorFilial = + calcularValoresPorMesPorFilial(items); + + // Linha do grupo (Level 0) + rows.push({ + type: 'grupo', + level: 0, + grupo: items[0]?.grupo || codgrupo, + codigo_grupo: codgrupo, + total: totalGrupo, + isExpanded: true, // Sempre expandido na exportação + valoresPorMes: valoresGrupoPorMes, + valoresPorMesPorFilial: valoresGrupoPorMesPorFilial, + percentuaisPorMes: calcularPercentuaisPorMes( + valoresGrupoPorMes, + codgrupo + ), + percentuaisPorMesPorFilial: calcularPercentuaisPorMesPorFilial( + valoresGrupoPorMesPorFilial, + codgrupo + ), + percentualTotal: calcularPercentualTotal(totalGrupo, codgrupo), + }); + + // SEMPRE incluir todas as contas (não depende de expandedGrupos) + // Agrupar por conta dentro do grupo + const contas = items.reduce((acc, item) => { + const conta = item.conta || ''; + if (!conta) return acc; + if (!acc[conta]) { + acc[conta] = []; + } + acc[conta].push(item); + return acc; + }, {} as Record); + + // Ordenar contas por CODCONTA + const sortedContas = Object.entries(contas).sort( + ([contaA, itemsA], [contaB, itemsB]) => { + const codcontaA = itemsA[0]?.codigo_conta || 0; + const codcontaB = itemsB[0]?.codigo_conta || 0; + + if (codcontaA && codcontaB) { + return codcontaA - codcontaB; + } + + return contaA.localeCompare(contaB); + } + ); + + sortedContas.forEach(([conta, contaItems]) => { + const totalConta = contaItems.reduce( + (sum, item) => sum + parseFloat(item.valor), + 0 + ); + const valoresContaPorMes = calcularValoresPorMes(contaItems); + const valoresContaPorMesPorFilial = + calcularValoresPorMesPorFilial(contaItems); + + // Linha da conta (Level 1) + rows.push({ + type: 'conta', + level: 1, + grupo: items[0]?.grupo || codgrupo, + codigo_grupo: codgrupo, + conta, + codigo_conta: contaItems[0]?.codigo_conta, + total: totalConta, + isExpanded: false, + valoresPorMes: valoresContaPorMes, + valoresPorMesPorFilial: valoresContaPorMesPorFilial, + percentuaisPorMes: calcularPercentuaisPorMes( + valoresContaPorMes, + codgrupo + ), + percentuaisPorMesPorFilial: calcularPercentuaisPorMesPorFilial( + valoresContaPorMesPorFilial, + codgrupo + ), + percentualTotal: calcularPercentualTotal(totalConta, codgrupo), + }); + }); + + // Adicionar linha calculada "MARGEM BRUTA" após o grupo 02 + // Verificar se é o último grupo ou se o próximo grupo é maior que 02 + const proximoCodigo = sortedGrupos[index + 1]?.[0]; + const proximoNumero = proximoCodigo ? parseInt(proximoCodigo) : 999; + + if ( + codgrupo === '02' || + (parseInt(codgrupo) === 2 && proximoNumero > 2) + ) { + // Calcular MARGEM BRUTA = CODGRUPO 01 + CODGRUPO 02 + const valoresGrupo01 = valoresPorGrupo['01'] || {}; + const valoresGrupo02 = valoresPorGrupo['02'] || {}; + + // Calcular valores por mês para MARGEM BRUTA + const valoresMargemPorMes: Record = {}; + mesesDisponiveis.forEach((mes) => { + const valor01 = valoresGrupo01[mes] || 0; + const valor02 = valoresGrupo02[mes] || 0; + valoresMargemPorMes[mes] = valor01 + valor02; + }); + + // Calcular valores por mês e por filial para MARGEM BRUTA + const valoresMargemPorMesPorFilial: Record< + string, + Record + > = {}; + const valoresGrupo01PorFilial = gruposPorCodigo['01'] + ? calcularValoresPorMesPorFilial(gruposPorCodigo['01']) + : {}; + const valoresGrupo02PorFilial = gruposPorCodigo['02'] + ? calcularValoresPorMesPorFilial(gruposPorCodigo['02']) + : {}; + + // Extrair filiais únicas dos valores calculados + const primeiroMes = mesesDisponiveis[0] || ''; + const filiaisDisponiveis = [ + ...new Set([ + ...Object.keys(valoresGrupo01PorFilial[primeiroMes] || {}), + ...Object.keys(valoresGrupo02PorFilial[primeiroMes] || {}), + ]), + ]; + + mesesDisponiveis.forEach((mes) => { + valoresMargemPorMesPorFilial[mes] = {}; + filiaisDisponiveis.forEach((filial) => { + const valor01 = valoresGrupo01PorFilial[mes]?.[filial] || 0; + const valor02 = valoresGrupo02PorFilial[mes]?.[filial] || 0; + valoresMargemPorMesPorFilial[mes][filial] = valor01 + valor02; + }); + }); + + // Calcular total + const totalMargem = Object.values(valoresMargemPorMes).reduce( + (sum, val) => sum + val, + 0 + ); + + // Armazenar valores da MARGEM BRUTA para uso posterior no RESULTADO LOJA + valoresMargemBrutaPorMes = valoresMargemPorMes; + valoresMargemBrutaPorMesPorFilial = valoresMargemPorMesPorFilial; + totalMargemBruta = totalMargem; + + // Adicionar linha calculada + rows.push({ + type: 'calculado', + level: 0, + grupo: 'MARGEM BRUTA', + codigo_grupo: 'MARGEM', + total: totalMargem, + isExpanded: false, + valoresPorMes: valoresMargemPorMes, + valoresPorMesPorFilial: valoresMargemPorMesPorFilial, + percentuaisPorMes: calcularPercentuaisPorMes( + valoresMargemPorMes, + 'MARGEM' + ), + percentuaisPorMesPorFilial: calcularPercentuaisPorMesPorFilial( + valoresMargemPorMesPorFilial, + 'MARGEM' + ), + percentualTotal: calcularPercentualTotal(totalMargem, 'MARGEM'), + isCalculado: true, + }); + } + + // Adicionar linha calculada "RESULTADO LOJA" após o grupo 04 (DESPESAS) + // Verificar se é o último grupo ou se o próximo grupo é maior que 04 + const proximoCodigoDespesas = sortedGrupos[index + 1]?.[0]; + const proximoNumeroDespesas = proximoCodigoDespesas + ? parseInt(proximoCodigoDespesas) + : 999; + + if ( + (codgrupo === '04' || + (parseInt(codgrupo) === 4 && proximoNumeroDespesas > 4)) && + valoresMargemBrutaPorMes !== null && + valoresMargemBrutaPorMesPorFilial !== null && + totalMargemBruta !== null + ) { + // Calcular RESULTADO LOJA = MARGEM BRUTA + DESPESAS (grupo 04) + const valoresGrupo04 = valoresPorGrupo['04'] || {}; + + // Calcular valores por mês para RESULTADO LOJA + const valoresResultadoPorMes: Record = {}; + mesesDisponiveis.forEach((mes) => { + const valorMargem = valoresMargemBrutaPorMes![mes] || 0; + const valorDespesas = valoresGrupo04[mes] || 0; + valoresResultadoPorMes[mes] = valorMargem + valorDespesas; + }); + + // Calcular valores por mês e por filial para RESULTADO LOJA + const valoresResultadoPorMesPorFilial: Record< + string, + Record + > = {}; + const valoresGrupo04PorFilial = gruposPorCodigo['04'] + ? calcularValoresPorMesPorFilial(gruposPorCodigo['04']) + : {}; + + // Extrair filiais únicas dos valores calculados + const primeiroMes = mesesDisponiveis[0] || ''; + const filiaisDisponiveis = [ + ...new Set([ + ...Object.keys( + valoresMargemBrutaPorMesPorFilial![primeiroMes] || {} + ), + ...Object.keys(valoresGrupo04PorFilial[primeiroMes] || {}), + ]), + ]; + + mesesDisponiveis.forEach((mes) => { + valoresResultadoPorMesPorFilial[mes] = {}; + filiaisDisponiveis.forEach((filial) => { + const valorMargem = + valoresMargemBrutaPorMesPorFilial![mes]?.[filial] || 0; + const valorDespesas = valoresGrupo04PorFilial[mes]?.[filial] || 0; + valoresResultadoPorMesPorFilial[mes][filial] = + valorMargem + valorDespesas; + }); + }); + + // Calcular total + const totalResultado = Object.values(valoresResultadoPorMes).reduce( + (sum, val) => sum + val, + 0 + ); + + // Adicionar linha calculada + rows.push({ + type: 'calculado', + level: 0, + grupo: 'RESULTADO LOJA', + codigo_grupo: 'RESULTADO', + total: totalResultado, + isExpanded: false, + valoresPorMes: valoresResultadoPorMes, + valoresPorMesPorFilial: valoresResultadoPorMesPorFilial, + percentuaisPorMes: calcularPercentuaisPorMes( + valoresResultadoPorMes, + 'RESULTADO' + ), + percentuaisPorMesPorFilial: calcularPercentuaisPorMesPorFilial( + valoresResultadoPorMesPorFilial, + 'RESULTADO' + ), + percentualTotal: calcularPercentualTotal( + totalResultado, + 'RESULTADO' + ), + isCalculado: true, + }); + } + }); + + return rows; + }, [ + data, + mesesDisponiveis, + calcularValoresPorMes, + calcularValoresPorMesPorFilial, + calcularPercentuaisPorMes, + calcularPercentuaisPorMesPorFilial, + calcularPercentualTotal, + ]); + const exportarXLSX = () => { if (!data.length) { console.log('⚠️ Nenhum dado para exportar'); return; } - const dadosCompletosExpandidos = buildHierarchicalData(); + console.log('📊 Exportando TODOS os dados expandidos para XLSX...'); + + const dadosCompletosExpandidos = buildHierarchicalDataCompleta(); const dadosExportacao = dadosCompletosExpandidos.map((row, index) => { const linha: any = {