DealerBalancete

Ajusta a exibição do balancete

// ==UserScript==
// @name         DealerBalancete
// @namespace    http://tampermonkey.net/
// @version      1.1
// @description  Ajusta a exibição do balancete
// @author       Igor Lima
// @license      MIT
// @match        http*://*.dealernetworkflow.com.br/ContabilidadeWF/aprc_reportingservices.aspx*
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    // Adiciona estilos CSS para efeitos de hover e agrupamento
    const estilos = `
        <style id="estilos-agrupador-contas">
        @import url('https://fonts.googleapis.com/css2?family=Atkinson+Hyperlegible&display=swap');
            .grupo-conta {
                transition: background-color 0.2s ease;
                cursor: pointer;
            }

            .conta-nivel-1 { /*border-left: 1px solid #e74c3c;*/ }
            .conta-nivel-2 { /*border-left: 1px solid #f39c12;*/ }
            .conta-nivel-3 { /*border-left: 1px solid #27ae60;*/ }
            .conta-nivel-4 { /*border-left: 1px solid #3498db;*/ }
            .conta-nivel-5 { /*border-left: 1px solid #9b59b6;*/ }
            .conta-nivel-6 { /*border-left: 1px solid #e67e22;*/ }

            .grupo-conta:hover {
                background-color: rgba(52, 152, 219, 0.1) !important;
            }

            .grupo-conta.destacado {
                background-color: rgba(52, 152, 219, 0.2) !important;
            }

            .grupo-conta.pai-destacado {
                background-color: rgba(46, 204, 113, 0.1) !important;
            }

            .grupo-conta.filho-destacado {
                background-color: rgba(241, 196, 15, 0.1) !important;
            }

            .info-conta {
                font-size: 0.8em;
                color: #666;
                margin-left: 10px;
            }

            #oReportCell {
                width: 90vw !important;
            }

            .r9,
            table {
                width: 90vw !important;
            }

            .r9 table td, #oReportCell table td div {
                font-size: 13pt;
                font-family: Atkinson Hyperlegible;
                text-align: left;
            }

            .r9 table tr td a,
            .r9 table tr td span {
                font-size: 12pt !important;
                font-weight: normal !important;
                /*text-decoration: underline;*/
                font-family: Atkinson Hyperlegible;
            }
        </style>
    `;

    // Injeta os estilos na página
    document.head.insertAdjacentHTML('beforeend', estilos);

    // Padrão regex para corresponder códigos de conta hierárquicos
    const padraoCodigoConta = /^(\d+)(?:\.(\d+))?(?:\.(\d+))?(?:\.(\d+))?(?:\.(\d+))?$/;

    // Função para analisar código da conta e retornar informações da hierarquia
    function analisarCodigoConta(codigo) {
        const correspondencia = codigo.trim().match(padraoCodigoConta);
        if (!correspondencia) return null;

        const partes = [];
        for (let i = 1; i < correspondencia.length; i++) {
            if (correspondencia[i]) partes.push(correspondencia[i]);
        }

        return {
            completo: codigo.trim(),
            partes: partes,
            nivel: partes.length,
            pai: partes.length > 1 ? partes.slice(0, -1).join('.') : null
        };
    }

    // Função para verificar se uma conta é pai de outra
    function ehPaiDe(pai, filho) {
        return filho.completo.startsWith(pai.completo + '.');
    }

    // Função para obter todas as contas relacionadas (pais e filhos)
    function obterContasRelacionadas(contaAlvo, todasContas) {
        const relacionadas = {
            pais: [],
            filhos: [],
            irmaos: []
        };

        todasContas.forEach(conta => {
            if (conta.completo === contaAlvo.completo) return;

            // Verifica se é um pai
            if (contaAlvo.completo.startsWith(conta.completo + '.')) {
                relacionadas.pais.push(conta);
            }

            // Verifica se é um filho
            if (ehPaiDe(contaAlvo, conta)) {
                relacionadas.filhos.push(conta);
            }

            // Verifica se é irmão (mesmo pai)
            if (contaAlvo.pai && conta.pai === contaAlvo.pai) {
                relacionadas.irmaos.push(conta);
            }
        });

        return relacionadas;
    }

    // Função para processar a tabela do relatório
    function processarTabelaRelatorio() {
        const celulaRelatorio = document.getElementById('oReportCell');
        if (!celulaRelatorio) {
            console.log('Célula do relatório não encontrada, tentando novamente...');
            return false;
        }

        const tabelas = celulaRelatorio.querySelectorAll('table');
        if (tabelas.length === 0) {
            console.log('Nenhuma tabela encontrada na célula do relatório, tentando novamente...');
            return false;
        }

        const contas = [];
        const elementosContas = new Map();

        // Processa cada tabela para encontrar códigos de conta
        tabelas.forEach(tabela => {
            const linhas = tabela.querySelectorAll('tr');
            linhas.forEach(linha => {
                const celulas = linha.querySelectorAll('td');
                if (celulas.length > 0) {
                    const primeiraCelula = celulas[0];
                    const texto = primeiraCelula.textContent.trim();
                    const conta = analisarCodigoConta(texto);

                    if (conta) {
                        contas.push(conta);
                        elementosContas.set(conta.completo, {
                            elemento: linha,
                            celula: primeiraCelula,
                            conta: conta
                        });

                        // Adiciona classes CSS
                        linha.classList.add('grupo-conta');
                        linha.classList.add(`conta-${conta.completo.replace(/\./g, '-')}`);
                        linha.classList.add(`conta-nivel-${conta.nivel}`);

                        // Adiciona informações da conta à célula
                        //const info = document.createElement('span');
                        //info.className = 'info-conta';
                        //info.textContent = `(Nível ${conta.nivel})`;
                        //primeiraCelula.appendChild(info);
                    }
                }
            });
        });

        // Adiciona efeitos de hover e interações
        elementosContas.forEach((dados, codigoConta) => {
            const { elemento, conta } = dados;

            elemento.addEventListener('mouseenter', function() {
                // Limpa destaques anteriores
                document.querySelectorAll('.grupo-conta').forEach(el => {
                    el.classList.remove('destacado', 'pai-destacado', 'filho-destacado');
                });

                // Destaca elemento atual
                this.classList.add('destacado');

                // Obtém contas relacionadas
                const relacionadas = obterContasRelacionadas(conta, contas);

                // Destaca pais
                relacionadas.pais.forEach(contaPai => {
                    const elementoPai = elementosContas.get(contaPai.completo);
                    if (elementoPai) {
                        elementoPai.elemento.classList.add('pai-destacado');
                    }
                });

                // Destaca filhos
                relacionadas.filhos.forEach(contaFilho => {
                    const elementoFilho = elementosContas.get(contaFilho.completo);
                    if (elementoFilho) {
                        elementoFilho.elemento.classList.add('filho-destacado');
                    }
                });
            });

            elemento.addEventListener('mouseleave', function() {
                // Remove destaques após um pequeno atraso
                setTimeout(() => {
                    if (!document.querySelector('.grupo-conta:hover')) {
                        document.querySelectorAll('.grupo-conta').forEach(el => {
                            el.classList.remove('destacado', 'pai-destacado', 'filho-destacado');
                        });
                    }
                }, 100);
            });

            // Adiciona funcionalidade de clique para recolher/expandir
            elemento.addEventListener('click', function() {
                const relacionadas = obterContasRelacionadas(conta, contas);
                const estaRecolhido = this.dataset.recolhido === 'true';

                if (relacionadas.filhos.length > 0) {
                    relacionadas.filhos.forEach(contaFilho => {
                        const elementoFilho = elementosContas.get(contaFilho.completo);
                        if (elementoFilho) {
                            if (estaRecolhido) {
                                elementoFilho.elemento.style.display = '';
                            } else {
                                elementoFilho.elemento.style.display = 'none';
                            }
                        }
                    });

                    this.dataset.recolhido = !estaRecolhido;
                    this.style.fontWeight = estaRecolhido ? 'normal' : 'bold';
                }
            });
        });

        console.log(`Processadas ${contas.length} códigos de conta`);
        return true;
    }

    // Função para aguardar o relatório carregar e então processá-lo
    function inicializarQuandoPronto() {
        let tentativas = 0;
        const maxTentativas = 20;

        function tentarProcessar() {
            tentativas++;
            if (processarTabelaRelatorio()) {
                console.log('Agrupador de contas inicializado com sucesso');
            } else if (tentativas < maxTentativas) {
                setTimeout(tentarProcessar, 1000);
            } else {
                console.log('Falha ao inicializar agrupador de contas após tentativas máximas');
            }
        }

        tentarProcessar();
    }

    // Inicializa quando DOM estiver pronto
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', inicializarQuandoPronto);
    } else {
        inicializarQuandoPronto();
    }

    // Também observa mudanças de conteúdo dinâmico
    const observador = new MutationObserver(function(mutacoes) {
        mutacoes.forEach(function(mutacao) {
            if (mutacao.type === 'childList' && mutacao.addedNodes.length > 0) {
                // Verifica se o conteúdo do relatório foi atualizado
                const celulaRelatorio = document.getElementById('oReportCell');
                if (celulaRelatorio && mutacao.target.contains && mutacao.target.contains(celulaRelatorio)) {
                    setTimeout(processarTabelaRelatorio, 500);
                }
            }
        });
    });

    observador.observe(document.body, {
        childList: true,
        subtree: true
    });

})();