Revisão estrutura tabela - Relatório Contábil
This commit is contained in:
parent
3c396cbaa5
commit
fcb3aec5b9
@ -96,7 +96,9 @@
|
||||
"Bash(cp /tmp/pid_test_iripara.py \"C:\\\\Users\\\\Depaula\\\\AppData\\\\Local\\\\Temp\\\\claude\\\\c--Users-Depaula-Documents-Portal\\\\cf4a6caf-9798-42a6-bbc8-a8ffbb3debf6\\\\scratchpad\\\\pid_test_iripara.py\")",
|
||||
"Bash(PYTHONPATH=\"C:\\\\Users\\\\Depaula\\\\Documents\\\\Portal\" .venv/Scripts/python.exe \"C:\\\\Users\\\\Depaula\\\\AppData\\\\Local\\\\Temp\\\\claude\\\\c--Users-Depaula-Documents-Portal\\\\cf4a6caf-9798-42a6-bbc8-a8ffbb3debf6\\\\scratchpad\\\\pid_test_iripara.py\")",
|
||||
"Bash(sed -i 's#/api/apuracoes-contabeis/26/#/api/contabil-apuracoes/26/#' \"C:\\\\Users\\\\Depaula\\\\AppData\\\\Local\\\\Temp\\\\claude\\\\c--Users-Depaula-Documents-Portal\\\\cf4a6caf-9798-42a6-bbc8-a8ffbb3debf6\\\\scratchpad\\\\pid_test_iripara3.py\")",
|
||||
"Bash(PYTHONPATH=\"C:\\\\Users\\\\Depaula\\\\Documents\\\\Portal\" .venv/Scripts/python.exe \"C:\\\\Users\\\\Depaula\\\\AppData\\\\Local\\\\Temp\\\\claude\\\\c--Users-Depaula-Documents-Portal\\\\cf4a6caf-9798-42a6-bbc8-a8ffbb3debf6\\\\scratchpad\\\\pid_test_iripara3.py\")"
|
||||
"Bash(PYTHONPATH=\"C:\\\\Users\\\\Depaula\\\\Documents\\\\Portal\" .venv/Scripts/python.exe \"C:\\\\Users\\\\Depaula\\\\AppData\\\\Local\\\\Temp\\\\claude\\\\c--Users-Depaula-Documents-Portal\\\\cf4a6caf-9798-42a6-bbc8-a8ffbb3debf6\\\\scratchpad\\\\pid_test_iripara3.py\")",
|
||||
"Bash(awk '/class ContabilApuracao\\(List|Detail\\)Serializer/,/^class [A-Z]/' portal_api/serializers.py)",
|
||||
"Bash(grep -n \"Colapsadas.size ? new Set\\(\\)\\\\|Colapsadas = dcContasColapsadas.size\\\\|Colapsadas.size$\" static/js/dashboard-contabil.js)"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@ -391,3 +391,27 @@ Usuário reportou que o botão não apareceu, mesmo reiniciando o servidor e for
|
||||
Corrigido com uma migração de dados (`0077_backfill_achado_linha_analise_vertical`) que vincula os 78 achados antigos à linha certa, casando pela **assinatura contida na própria mensagem** do achado (descrição + percentual dos dois últimos meses) contra `ContabilLinhaAnaliseVertical.valores[-2:]`. Não re-executa `regras.py` de propósito — migração que importa código de app deixa de ser auto-contida se a regra mudar depois.
|
||||
|
||||
O primeiro algoritmo casava só por descrição, avançando um ponteiro na ordem de leitura, e a conferência contra produção reprovou: **4 dos 78 achados vincularam a linha errada**, justamente nas descrições repetidas entre centros de custo (`MATERIAIS E SERVIÇOSAPLICADOS NAOBRA`, 4 ocorrências) — ou seja, exatamente o caso que motivou o pedido do usuário teria ficado errado em silêncio. A regra dispara na ocorrência cujos percentuais estouram o limiar, que não é necessariamente a primeira. Com a assinatura completa: 78 de 78 casados, e a conferência final (comparar os percentuais da linha vinculada com os citados no texto de cada achado) deu 0 divergências. Migração já aplicada em produção; os 13 achados da apuração do print passaram a trazer o botão.
|
||||
|
||||
### 147. Excluir análise bloqueado depois de concluída
|
||||
|
||||
Pedido explícito do usuário (com print do histórico, numa linha "Concluída"): "quando estiver Concluída, a exclusão deve ficar bloqueada." Fecha a última ação destrutiva que ainda escapava da trava de "concluiu, não se mexe mais" — reprocessar, editar observação e tratar achado já eram bloqueados, mas excluir a análise inteira continuava liberado, o que é justamente o mais destrutivo dos três.
|
||||
|
||||
`ContabilApuracaoViewSet.perform_destroy()` recusa com 400 quando `status == "concluida"` (mensagem própria, não o `_contabil_garante_em_revisao`, cuja frase fala em editar observações/achados). Na lista, o ícone de lixeira some na linha concluída — mesmo padrão que o botão de reprocessar ao lado já usava, pra não misturar "some" e "aparece desabilitado" na mesma linha de ações. O clique em excluir também ganhou `try/catch` + `pidAlert`: o botão não aparece numa análise concluída, mas outra pessoa pode ter concluído depois da lista ter sido carregada, e aí o motivo precisa chegar na tela em vez de o clique não fazer nada.
|
||||
|
||||
Validado via `Client.force_login()` contra dados reais: DELETE numa apuração concluída → 400 e o registro continua no banco; DELETE numa em revisão → 204, seguiu funcionando normalmente.
|
||||
|
||||
**Incidente durante essa validação** (registrado de propósito, ver também a rodada 148 abaixo): o teste rodou dentro de `transaction.atomic()` com rollback forçado, o padrão usado o tempo todo aqui, mas `perform_destroy()` chama `instance.arquivo.delete(save=False)` — e **apagar arquivo do storage não é revertido por rollback de transação**. O registro da apuração 26 (PURE TECH ENERGY) voltou pelo rollback, o PDF anexado dela não. Nenhum dado analítico se perdeu (contas, DRE, Análise Vertical, os 57 achados, observações e validações estavam todos no banco) e nenhuma funcionalidade depende desse arquivo — `arquivo` não é exposto em nenhum serializer e `reprocessar()` sempre grava um upload novo, nunca lê o antigo —, mas o anexo original precisa ser reposto reanexando o mesmo PDF pelo botão "Reprocessar". Lição pra qualquer teste futuro de exclusão nesta base: rollback só protege o banco; efeito colateral em disco exige apuração descartável ou storage isolado.
|
||||
|
||||
### 148. Tabelas abrem com tudo expandido; o "+" virou "−"
|
||||
|
||||
Pedido explícito do usuário: "por padrão, trazer as tabelas com a expansão de todas as contas até o último nível. O comportamento do botão de + deve virar um − e recolher os níveis para que retorne no atual padrão que abre a tabela. O botão de reverter deve reverter ao novo padrão (todas expandidas)." Inverte o padrão de abertura que valia desde as primeiras rodadas nas 3 tabelas da revisão (Balancete, DRE e Análise Vertical).
|
||||
|
||||
Na prática o estado inicial passou a ser exatamente o que o antigo "+" produzia — por isso a mudança é pequena: `renderRevisao()` passa `new Set()` nos três conjuntos de colapso e o botão da primeira coluna aplica `dcColapsoPadrao()` (a visão compacta, que era o padrão de abertura). O atributo e a classe foram renomeados (`data-dc-expandir-tudo`/`dc-expandir-tudo-btn` → `data-dc-recolher-grupos`/`dc-recolher-grupos-btn`), já que "expandir tudo" passaria a descrever o oposto do que o botão faz; o ícone perdeu o traço vertical do "+" e os textos de tooltip/acessibilidade foram reescritos.
|
||||
|
||||
**Virou toggle logo em seguida, ainda na mesma rodada**: o usuário testou e pediu que "após apertar uma vez, o botão de − vira um + e retorna para o padrão anterior" — na primeira versão ele só recolhia, e voltar exigia achar o botão de restaurar na outra ponta do cabeçalho. O handler passou a alternar (`colapsadas.size ? new Set() : dcColapsoPadrao(...)`) e `dcAtualizaBotaoArvore()` troca ícone/tooltip/rótulo de acessibilidade no fim de cada render. A face do botão é **derivada** de quantos grupos estão recolhidos, não de um flag próprio: recolher uma única conta pelo toggle da própria linha já faz o botão virar "+", que devolve a tabela inteira. Simulado contra o Balancete real da apuração 27 (564 contas): abre em "−" com 564 visíveis → clique vira "+" com 29 → clique volta pra "−" com 564, estável em ciclo. Efeito colateral: o botão de restaurar passou a fazer o mesmo que a face "+" — mantido de propósito, é a "borracha" já conhecida de outras telas do Portal, mas dá pra remover se o usuário preferir.
|
||||
|
||||
O destaque das linhas não precisou de ajuste nenhum: `dcUltimaLevaVisivel()` com o conjunto vazio já marca as folhas, que é o comportamento que o "+" tinha. Simulado contra as 4 apurações reais de produção (replicando `dcColapsoPadrao`/`dcUltimaLevaVisivel` em Python, sem tocar no banco): no padrão novo todas as linhas ficam visíveis e o destaque bate exatamente com as folhas (Balancete da apuração 27: 564 visíveis, 443 destacadas = as 443 folhas), e o "−" reduz pra visão compacta (as mesmas 564 caem pra 29). Efeito esperado e aceito: as tabelas abrem bem mais longas do que antes.
|
||||
|
||||
**O relatório "Gerar Dashboard" não foi tocado** — continua nascendo recolhido (`colapsado_padrao` calculado server-side em `_contabil_arvore_contexto()`). É o documento que vai pro cliente, tem só o botão de restaurar (nunca teve "+"/"−") e mudar o que o cliente vê não foi pedido; virou o único lugar onde `dcColapsoPadrao`/`_CONTABIL_NIVEL_ABERTO_PADRAO` ainda é padrão de abertura. Se o usuário quiser o mesmo lá, é um ajuste separado.
|
||||
|
||||
Mudança só em `.js`/`.html`/`.css` — não exige reiniciar o `runserver`.
|
||||
|
||||
@ -74,7 +74,9 @@ Diferente de `IndicadorApuracaoViewSet`/`ImportacaoPlanoSaudeViewSet` (onde a ch
|
||||
|
||||
**Balancete e DRE usam a mesma árvore recolhível** (`dashboard-contabil.js`): o Balancete já construía uma árvore expansível a partir do nível de indentação derivado do código de classificação (`dcContaNivel()`, contando segmentos separados por `.`) — a DRE não tem código de classificação (ver "Extração do PDF" acima), mas já carregava `nivel` pronto do backend (`ContabilLinhaDre.nivel`, derivado do `x0` de cada linha no PDF), então `renderDre()` reaproveita exatamente o mesmo algoritmo de `renderContas()` (pilha de níveis recolhidos, "tem filhos" = a próxima linha tem nível maior) só que sobre `linha.nivel` direto, sem precisar de um `dcContaNivel` equivalente. Reaproveita as mesmas classes CSS do toggle (`.dc-conta-toggle`/`.dc-conta-toggle-spacer`/`.dc-conta-desc-cell`, `dashboard-contabil.css`) — o nome genérico ("conta") já cobre as duas árvores, não precisou de classe nova. Estado de colapso é independente por aba (`dcContasColapsadas`/`dcDreColapsadas`, dois `Set()`).
|
||||
|
||||
**Nasce recolhida a partir do 3º segmento do código** (pedido explícito do usuário, pra reduzir a poluição visual de uma apuração com muitas contas analíticas — limiar ajustado numa rodada seguinte, ver abaixo): em vez de `renderRevisao()` reiniciar os dois `Set()` vazios (tudo expandido), `dcColapsoPadrao(itens, nivelFn)` os pré-popula com os ids de todo item que tem filhos **e** está no nível `PID_DC_NIVEL_ABERTO_PADRAO` (`2`) ou além — ex. a conta `1.01.01` (3 segmentos, nível 2) aparece aberta, mas seus filhos (`1.01.01.001`, nível 3) ficam ocultos até o contador clicar pra expandir; se expandido, um filho de nível 3 que também tenha netos nasce recolhido de novo pelo mesmo critério, então "nível 3 em diante" precisa sempre de um clique a mais, não só a primeira camada. Mesmo limiar aplicado à DRE, sobre `Math.max(0, linha.nivel)` — decisão confirmada com o usuário (a princípio o pedido citava só o Balancete, mas como a DRE reaproveita o mesmo algoritmo, o mesmo comportamento faz sentido nela também). O relatório "Gerar Dashboard" replica esse mesmo estado inicial (ver abaixo) — não é só a tela de revisão. `PID_DC_NIVEL_ABERTO_PADRAO` (JS) e `_CONTABIL_NIVEL_ABERTO_PADRAO` (`views.py`) são a mesma constante conceitual duplicada nos dois lados (um é SPA, o outro HTML renderizado uma vez) — mudar o limiar exige ajustar os dois.
|
||||
**Nasce com a árvore inteira expandida** (rodada 148, pedido explícito do usuário — inverte o padrão descrito no parágrafo seguinte, que valia até então): `renderRevisao()` reinicia os três `Set()` de colapso vazios, e o estado compacto de `dcColapsoPadrao()` virou o botão "−" do cabeçalho, aplicado sob demanda (ver "Cabeçalho: dois botões" abaixo).
|
||||
|
||||
**Estado compacto (`dcColapsoPadrao`), hoje só sob demanda pelo botão "−"** (era o padrão de abertura até a rodada 148, e continua sendo o padrão do relatório "Gerar Dashboard", que é server-side e não mudou): `dcColapsoPadrao(itens, nivelFn)` popula o `Set` com os ids de todo item que tem filhos **e** está no nível `PID_DC_NIVEL_ABERTO_PADRAO` (`2`) ou além — ex. a conta `1.01.01` (3 segmentos, nível 2) aparece aberta, mas seus filhos (`1.01.01.001`, nível 3) ficam ocultos até o contador clicar pra expandir; se expandido, um filho de nível 3 que também tenha netos nasce recolhido de novo pelo mesmo critério, então "nível 3 em diante" precisa sempre de um clique a mais, não só a primeira camada. Mesmo limiar aplicado à DRE, sobre `Math.max(0, linha.nivel)` — decisão confirmada com o usuário (a princípio o pedido citava só o Balancete, mas como a DRE reaproveita o mesmo algoritmo, o mesmo comportamento faz sentido nela também). O relatório "Gerar Dashboard" continua **nascendo** nesse estado (ver abaixo) — desde a rodada 148 é o único lugar onde ele é o padrão de abertura. `PID_DC_NIVEL_ABERTO_PADRAO` (JS) e `_CONTABIL_NIVEL_ABERTO_PADRAO` (`views.py`) são a mesma constante conceitual duplicada nos dois lados (um é SPA, o outro HTML renderizado uma vez) — mudar o limiar exige ajustar os dois.
|
||||
|
||||
**Destaque acompanha todo grupo já expandido** (pedido explícito do usuário, mesma rodada do ajuste de limiar acima, com o mecanismo revisado na rodada 140 abaixo): ao expandir uma conta/linha, as linhas que acabaram de ficar visíveis (só os filhos **diretos**, não os netos — que continuam recolhidos pelo limiar acima) ganham um realce dourado (`.dc-conta-row--destaque`), e **mais nada** fica destacado enquanto houver grupo aberto. Dois `Set()` por árvore (os 6 resetados em `renderRevisao()` e no botão "Restaurar formatação"): `dcContasExpandidos`/`dcDreExpandidos`/`dcAvExpandidos` guardam os ids dos grupos que o contador expandiu manualmente e que continuam expandidos, e `dcContasDestaque`/`dcDreDestaque`/`dcAvDestaque` guardam o resultado **derivado** (as linhas de fato destacadas), sempre recalculado por `dcDestaqueGrupos(itens, nivelFn, colapsadas, expandidos)`:
|
||||
|
||||
@ -90,9 +92,11 @@ O handler de clique do toggle guarda `estavaColapsada = colapsadas.has(id)` **an
|
||||
|
||||
Correção final é a descrita acima (`dcDestaqueGrupos()` com a base padrão **descartada** enquanto houver grupo aberto). Validada simulando o algoritmo em Python contra as contas reais da apuração `2021`/`08-2026`, reproduzindo o roteiro exato do usuário: expandir "CAIXA E EQUIVALENTES DE CAIXA" destaca só seus 2 filhos (resto da tabela limpo); expandir "CLIENTES" em seguida mantém os 2 primeiros e soma "DUPLICATAS A RECEBER"; fechar "CLIENTES" volta aos 2 primeiros; fechar "CAIXA" devolve exatamente o `Set` de destaque inicial (comparação de igualdade entre os dois conjuntos bateu). Mesmo ajuste replicado em `pidDcrArvore()` (`dashboard-contabil-relatorio.html`, réplica em JS puro desta mesma lógica no relatório "Gerar Dashboard", com `calculaDestaque()`/`expandidos`/`descendentes()` espelhando as funções do JS) — os dois lados são mantidos manualmente em sincronia, ver "Balancete e D.R.E. têm árvore recolhível igual à tela de revisão" abaixo.
|
||||
|
||||
**Botão "+" (expandir tudo) no cabeçalho da primeira coluna** (pedido explícito do usuário, rodada seguinte — a ideia inicial incluía um "−" que recolhesse um nível por vez, descartada pelo próprio usuário na mesma conversa, "poderia apenas um botão"): `.dc-expandir-tudo-btn` (`data-dc-expandir-tudo="balancete|dre|analise-vertical"`), dentro de um `.dc-th-linha.dc-th-linha--inicio` (modificador novo, só troca o `justify-content` pra `flex-start` — o botão vem **antes** do rótulo, ao contrário do "Restaurar formatação", que fica colado na borda direita da última coluna). Abre a árvore inteira de uma vez (`dc*Colapsadas = new Set()`), até a conta analítica mais funda, nas 3 tabelas (cada uma com o seu botão, mesmo motivo do botão de restaurar: estados de colapso independentes). **Não é um toggle** — o caminho de volta é o botão "Restaurar formatação padrão" que já existe na coluna "Observação" da mesma tabela.
|
||||
**Cabeçalho: dois botões por tabela, em pontas opostas** — `.dc-recolher-grupos-btn` (`data-dc-recolher-grupos="balancete|dre|analise-vertical"`) na primeira coluna, dentro de um `.dc-th-linha.dc-th-linha--inicio` (modificador que só troca o `justify-content` pra `flex-start` — este botão vem **antes** do rótulo, ao contrário do "Restaurar formatação", colado na borda direita da última coluna), e `.dc-reset-formatacao-btn` na coluna "Observação". Cada uma das 3 tabelas tem o seu par, porque os estados de colapso são independentes.
|
||||
|
||||
Ponto não-óbvio: expandir tudo **zera** `dc*Expandidos` em vez de populá-lo com todos os grupos. Com o conjunto vazio, `dcDestaqueGrupos()` cai na leva padrão (`dcUltimaLevaVisivel`), que sem nada recolhido marca exatamente as **folhas** — validado contra a apuração real `2021`/`08-2026`: 133 contas visíveis, 74 destacadas, exatamente as 74 contas sem filhos (igualdade de conjuntos conferida). Popular `dc*Expandidos` com todos os grupos destacaria quase toda linha da tabela, que é o mesmo problema de "tudo destacado, nada se destaca" da tentativa falha nº 1 acima. O cabeçalho da Análise Vertical é montado em JS (`renderAnaliseVerticalHead()`, número de colunas varia com os meses), então lá o botão nasce no template string — nos outros dois é HTML fixo em `dashboard-contabil.html`; os listeners são delegados no `<thead>`, então sobrevivem ao `innerHTML` ser refeito a cada render.
|
||||
O botão da primeira coluna nasceu como "+" (expandir tudo) numa rodada em que as tabelas abriam recolhidas; na rodada 148 o padrão de abertura virou "tudo expandido" e ele virou um **toggle** de duas faces: mostra "−" e aplica `dcColapsoPadrao()` (a visão compacta) enquanto nada está recolhido, mostra "+" e zera (`dc*Colapsadas = new Set()`) assim que existe qualquer grupo recolhido. A face sai de `dcAtualizaBotaoArvore(chave, colapsadas, nomeTabela)`, chamada no fim de cada `render*()` — é **derivada de `colapsadas.size`**, não de um flag próprio, então continua correta quando o contador recolhe/expande uma linha pelo toggle dela, sem passar pelo cabeçalho. O botão de restaurar passou a fazer o mesmo que a face "+"; ficou redundante e foi mantido de propósito, por ser a "borracha" que o usuário já conhece de outras telas do Portal.
|
||||
|
||||
Ponto não-óbvio: os dois **zeram** `dc*Expandidos` em vez de populá-lo com todos os grupos. Com o conjunto vazio, `dcDestaqueGrupos()` cai na leva padrão (`dcUltimaLevaVisivel`), que sem nada recolhido marca exatamente as **folhas** — validado contra a apuração real `2021`/`08-2026`: 133 contas visíveis, 74 destacadas, exatamente as 74 contas sem filhos (igualdade de conjuntos conferida). Popular `dc*Expandidos` com todos os grupos destacaria quase toda linha da tabela, que é o mesmo problema de "tudo destacado, nada se destaca" da tentativa falha nº 1 acima. O cabeçalho da Análise Vertical é montado em JS (`renderAnaliseVerticalHead()`, número de colunas varia com os meses), então lá o botão nasce no template string — nos outros dois é HTML fixo em `dashboard-contabil.html`; os listeners são delegados no `<thead>`, então sobrevivem ao `innerHTML` ser refeito a cada render.
|
||||
|
||||
**Card de achado expande a conta usada no apontamento** (`renderAchados()`, pedido explícito do usuário): `achado.conta` (id, já vem no payload de `/api/contabil-apuracoes/{id}/`, junto de `conta_codigo`/`conta_descricao`) é resolvido pra objeto completo procurando em `apuracaoAtual.contas` (`.find((c) => c.id === achado.conta)`) — sem chamada de API extra, já que a apuração inteira (contas + linhas de DRE + achados) já vem de uma vez só nesse endpoint. Só achados vinculados a uma conta específica ganham o botão "Ver conta usada no apontamento" (`.dc-achado-card__toggle-conta`) — as duas regras gerais (`balanceamento_ativo_passivo`/`debito_credito_divergente`, `conta` nulo no model) não têm uma conta única por trás, então não mostram o toggle. Expandido, mostra código/descrição/saldo anterior/débito/crédito/saldo atual da conta (`.dc-achado-card__conta`, um `<dl>` em grid). Estado de expansão (`dcAchadosContaExpandida`, um `Set()` de ids de achado) segue o mesmo padrão de `dcContasColapsadas`/`dcDreColapsadas` — reiniciado em `renderRevisao()`.
|
||||
|
||||
@ -518,7 +522,7 @@ Pedido explícito do usuário a partir de um caso real: a regra `regra_variacao_
|
||||
**Frontend** (`dashboard-contabil.js`): `renderAchados()` mostra um botão "Ver na tabela" (`PID_DC_ICON_LOCALIZAR`, novo ícone de pin) ao lado do "Revisar", condicionado a `achado.conta != null || achado.linha_analise_vertical != null`. O clique chama `dcIrParaLinha(tipo, id)` (`tipo` é `"conta"` ou `"av"`, roteado pelo campo presente no achado) — a função:
|
||||
|
||||
1. Acha o índice da linha alvo no array certo (`apuracaoAtual.contas`/`apuracaoAtual.linhas_analise_vertical`, via `DC_IR_PARA_CONFIG`).
|
||||
2. Calcula só os **ancestrais** dela (`dcAncestraisIds()`, a mesma pilha de níveis usada em toda a árvore desta tela — `nivel > próximo? tem filho`) e tira só esses ids de `dcContasColapsadas`/`dcAvColapsadas`, não a árvore inteira (diferente do botão "+"/"Expandir tudo", que zera o Set inteiro) — só abre o necessário pra revelar a linha alvo, preservando o resto do estado de expansão que o contador já tinha montado.
|
||||
2. Calcula só os **ancestrais** dela (`dcAncestraisIds()`, a mesma pilha de níveis usada em toda a árvore desta tela — `nivel > próximo? tem filho`) e tira só esses ids de `dcContasColapsadas`/`dcAvColapsadas`, não a árvore inteira (diferente do botão "Restaurar formatação", que zera o Set inteiro) — só abre o necessário pra revelar a linha alvo, preservando o resto do estado de expansão que o contador já tinha montado.
|
||||
3. Marca `dcFocoLinha = { tipo, id }` (estado module-scope novo, sempre derivado/temporário — mesmo espírito de `dcContasDestaque`) e re-renderiza a tabela certa, que aplica a classe `.dc-conta-row--foco` só na linha marcada (`renderContas()`/`renderAnaliseVertical()` ganharam essa checagem, junto de um `data-dc-conta-row-id`/`data-dc-av-row-id` novo no `<tr>` pra dar pra selecionar a linha depois).
|
||||
4. Clica programaticamente no botão da aba certa (`#dc-tabs [data-dc-tab="balancete"|"analise-vertical"]`) — reaproveita o listener de troca de aba já existente, sem duplicar a lógica de mostrar/esconder painel.
|
||||
5. Num `requestAnimationFrame` (depois do painel já visível), `scrollIntoView({ behavior: "smooth", block: "center" })` na linha.
|
||||
@ -531,3 +535,24 @@ Pedido explícito do usuário a partir de um caso real: a regra `regra_variacao_
|
||||
**Backfill dos achados que já existiam** (migração `0077_backfill_achado_linha_analise_vertical`, mesma rodada): o campo nasceu na `0076`, então todo achado criado antes ficou nulo e **não** ganhava o botão. Na prática isso deixava o recurso invisível — das 4 apurações em produção, 3 tinham *só* achados de `variacao_atipica_dre` (a apuração que o usuário estava olhando tinha 13 de 13), e a única forma de repor o vínculo seria reprocessar, o que **exige reanexar o PDF**. A migração casa cada achado antigo com a linha certa usando a **assinatura extraída da própria mensagem** — descrição + percentual do penúltimo e do último mês (`Linha "X" da DRE foi de A% ... para B% ...`), os três conferidos contra `ContabilLinhaAnaliseVertical.valores[-2:]`. Não re-executa `regras.py` de propósito: migração que importa código de app muda de comportamento se a regra mudar depois, e esta precisa continuar auto-contida.
|
||||
|
||||
**Por que a assinatura completa, e não só a descrição**: a primeira versão do backfill casava por descrição avançando um ponteiro na ordem de leitura (os achados são criados percorrendo as linhas em ordem, então parecia suficiente). Conferido contra produção, **4 dos 78 achados apontaram pra linha errada** — exatamente as descrições repetidas em vários centros de custo (`MATERIAIS E SERVIÇOSAPLICADOS NAOBRA` aparece 4x na apuração 27), que é o caso que originou a rodada: a regra dispara na ocorrência cujos percentuais estouram o limiar, que não é necessariamente a primeira a partir do ponteiro. Com descrição+percentuais, os 78 casaram com a linha certa (conferido comparando os percentuais da linha vinculada com os citados no texto do achado: 0 divergências). O ponteiro continua no algoritmo, mas só como desempate final entre linhas que tenham descrição **e** percentuais idênticos — aí são indistinguíveis pelo dado e a ordem é o único critério que resta. Achado que não casa fica nulo de propósito (o card só não mostra o botão), nada é vinculado por aproximação.
|
||||
|
||||
### Excluir análise bloqueado depois de concluída (rodada 147)
|
||||
|
||||
Pedido explícito do usuário. `ContabilApuracaoViewSet.perform_destroy()` levanta `ValidationError` (400) quando `status == ContabilApuracao.STATUS_CONCLUIDA` — mensagem própria em vez de reusar `_contabil_garante_em_revisao()`, cuja frase fala em editar observações/achados. Fecha a última ação destrutiva fora da trava de "concluiu, não se mexe mais": reprocessar e editar observação/achado já eram bloqueados, excluir a análise inteira (a mais destrutiva das três) não era.
|
||||
|
||||
Frontend (`renderList()`): o ícone de lixeira **some** na linha concluída, mesmo padrão que o botão de reprocessar ao lado já usava — misturar "some" (reprocessar) e "aparece desabilitado" (excluir) na mesma linha de ações seria incoerente. O handler de `[data-dc-excluir]` ganhou `try/catch` + `pidAlert(e.message)`: a trava do servidor continua valendo pra uma lista carregada antes de outra pessoa concluir a análise, e nesse caso o motivo precisa aparecer na tela em vez de o clique não fazer nada.
|
||||
|
||||
**Cuidado ao testar exclusão nesta ViewSet**: `perform_destroy()` chama `instance.arquivo.delete(save=False)`, e apagar arquivo do storage **não é revertido** por `transaction.set_rollback(True)` — o padrão de teste usado no resto desta documentação protege só o banco. Validar o caminho "204" de exclusão contra uma apuração real custou o PDF anexado dela (o registro voltou pelo rollback, o arquivo não; ver CHANGELOG da rodada 147). Nenhum dado analítico depende desse arquivo (`arquivo` não é exposto em serializer nenhum e `reprocessar()` sempre grava um upload novo), mas um teste futuro desse caminho precisa de apuração descartável ou storage isolado.
|
||||
|
||||
### Tabelas abrem com tudo expandido; "+" virou "−" (rodada 148)
|
||||
|
||||
Pedido explícito do usuário: "por padrão, trazer as tabelas com a expansão de todas as contas até o último nível. O comportamento do botão de + deve virar um − e recolher os níveis para que retorne no atual padrão que abre a tabela. O botão de reverter deve reverter ao novo padrão (todas expandidas)."
|
||||
|
||||
Inverte o padrão que valia desde as primeiras rodadas (`dcColapsoPadrao()` no `renderRevisao()`): `renderRevisao()` passa `new Set()` nos três `dc*Colapsadas`, e o estado compacto virou ação sob demanda. O atributo/classe foram renomeados (`dc-expandir-tudo-btn` → `dc-recolher-grupos-btn`) porque "expandir tudo" descreveria o oposto do que o botão faz no estado inicial.
|
||||
|
||||
**Refinamento pedido logo em seguida, na mesma rodada** ("após apertar uma vez, o botão de − vira um + e retorna para o padrão anterior"): a primeira versão não era toggle — o "−" só recolhia, e voltar exigia o botão de restaurar, na outra ponta do cabeçalho. Agora o handler alterna (`colapsadas.size ? new Set() : dcColapsoPadrao(...)`) e `dcAtualizaBotaoArvore()` troca ícone/`title`/`aria-label` a cada render. Simulado contra o Balancete real da apuração 27 (564 contas): abre em "−" com 564 linhas visíveis, clique → "+" com 29, clique → "−" com 564, estável em ciclo; e recolhendo **uma** conta pelo toggle da própria linha o botão já vira "+", que devolve as 564 — o efeito de derivar a face do estado em vez de guardar um flag.
|
||||
|
||||
O destaque não precisou de nenhum ajuste: `dcUltimaLevaVisivel()` com o `Set` vazio já marca as folhas, que é o comportamento que o "+" tinha e que o usuário aprovou. Simulado contra as 4 apurações reais de produção (replicando `dcColapsoPadrao`/`dcUltimaLevaVisivel` em Python): no padrão novo todas as linhas ficam visíveis e o destaque bate com as folhas (Balancete da apuração 27: 564 visíveis, 443 destacadas = as 443 folhas), e o botão "−" reduz pra visão compacta (as mesmas 564 caem pra 29 visíveis). Efeito colateral esperado e aceito: as tabelas abrem bem mais longas (o Balancete dessa apuração passa de 29 pra 564 linhas de saída).
|
||||
|
||||
**O relatório "Gerar Dashboard" não mudou** — continua nascendo recolhido pelo `colapsado_padrao` calculado server-side (`_contabil_arvore_contexto()`, `_CONTABIL_NIVEL_ABERTO_PADRAO`). É a única tela onde `dcColapsoPadrao` ainda é padrão de abertura, e não foi tocada de propósito: é o documento que vai pro cliente, tem só o botão de restaurar (nunca teve o "+"/"−"), e mudar o que o cliente vê não foi pedido. `PID_DC_NIVEL_ABERTO_PADRAO` (JS) e `_CONTABIL_NIVEL_ABERTO_PADRAO` (Python) continuam sendo a mesma constante conceitual duplicada, agora com papéis diferentes em cada lado (sob demanda na revisão, padrão no relatório).
|
||||
|
||||
|
||||
@ -4069,6 +4069,18 @@ class ContabilApuracaoViewSet(viewsets.ModelViewSet):
|
||||
return ContabilApuracaoDetailSerializer
|
||||
|
||||
def perform_destroy(self, instance: ContabilApuracao) -> None:
|
||||
"""Análise **Concluída** não pode mais ser excluída — pedido explícito
|
||||
do usuário, mesma trava de "concluiu, não se mexe mais" que já valia
|
||||
pra reprocessar e pra editar observação/achado
|
||||
(`_contabil_garante_em_revisao`). Mensagem própria em vez de reusar o
|
||||
helper porque a dele fala em editar observações/achados, que não é o
|
||||
caso aqui. Esconder o botão na lista é só UX — quem decide é isto,
|
||||
inclusive pra uma tela aberta antes de outra pessoa concluir a
|
||||
análise."""
|
||||
if instance.status == ContabilApuracao.STATUS_CONCLUIDA:
|
||||
raise ValidationError(
|
||||
{"detail": "Esta análise já foi concluída — não é mais possível excluí-la."}
|
||||
)
|
||||
instance.arquivo.delete(save=False)
|
||||
instance.delete()
|
||||
|
||||
|
||||
@ -1924,7 +1924,7 @@
|
||||
/* Menor que o .icon-btn padrão (38px) — vive dentro de uma célula de
|
||||
cabeçalho de tabela, não pode competir em tamanho com o texto da coluna. */
|
||||
.dc-reset-formatacao-btn,
|
||||
.dc-expandir-tudo-btn {
|
||||
.dc-recolher-grupos-btn {
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
flex-shrink: 0;
|
||||
|
||||
@ -118,6 +118,14 @@ const PID_DC_ICON_LIXEIRA =
|
||||
'<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M4 7h16M9 7V4h6v3M6 7l1 13a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1l1-13" stroke-linecap="round" stroke-linejoin="round"/></svg>';
|
||||
const PID_DC_ICON_HISTORICO =
|
||||
'<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 3v5h5"/><path d="M3.05 13A9 9 0 1 0 6 5.3L3 8"/><path d="M12 7v5l4 2"/></svg>';
|
||||
// As duas faces do botão de árvore no cabeçalho da primeira coluna das 3
|
||||
// tabelas da revisão (ver dcAtualizaBotaoArvore) — é um toggle: "−" enquanto
|
||||
// a árvore está toda aberta (o padrão), "+" assim que existe qualquer grupo
|
||||
// recolhido.
|
||||
const PID_DC_ICON_RECOLHER_ARVORE =
|
||||
'<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><path d="M5 12h14"/></svg>';
|
||||
const PID_DC_ICON_EXPANDIR_ARVORE =
|
||||
'<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><path d="M12 5v14"/><path d="M5 12h14"/></svg>';
|
||||
// Usado pelo botão "Ver na tabela" dos cards de achado (ver renderAchados) —
|
||||
// mesma semântica de "localizar um ponto", reaproveitado como pin de mapa.
|
||||
const PID_DC_ICON_LOCALIZAR =
|
||||
@ -554,9 +562,13 @@ document.addEventListener("DOMContentLoaded", async () => {
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12a9 9 0 1 1-2.64-6.36"/><path d="M21 3v6h-6"/></svg>
|
||||
</button>`
|
||||
}
|
||||
<button type="button" class="icon-btn" data-dc-excluir="${apuracao.id}" aria-label="Excluir" title="Excluir">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M4 7h16M9 7V4h6v3M6 7l1 13a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1l1-13" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
||||
</button>
|
||||
${
|
||||
apuracao.status === "concluida"
|
||||
? ""
|
||||
: `<button type="button" class="icon-btn" data-dc-excluir="${apuracao.id}" aria-label="Excluir" title="Excluir">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M4 7h16M9 7V4h6v3M6 7l1 13a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1l1-13" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
||||
</button>`
|
||||
}
|
||||
</td>
|
||||
`;
|
||||
body.appendChild(tr);
|
||||
@ -761,8 +773,17 @@ document.addEventListener("DOMContentLoaded", async () => {
|
||||
const excluirBtn = event.target.closest("[data-dc-excluir]");
|
||||
if (excluirBtn) {
|
||||
if (!(await pidConfirm("Excluir esta análise? Essa ação não pode ser desfeita.", { perigoso: true }))) return;
|
||||
await pidExcluirApuracaoContabil(Number(excluirBtn.getAttribute("data-dc-excluir")));
|
||||
// O botão nem aparece numa análise concluída, mas o servidor recusa de
|
||||
// novo (ver ContabilApuracaoViewSet.perform_destroy) — pode ter sido
|
||||
// concluída por outra pessoa depois desta lista ter sido carregada, e aí
|
||||
// o motivo precisa chegar na tela em vez de o clique não fazer nada.
|
||||
try {
|
||||
await pidExcluirApuracaoContabil(Number(excluirBtn.getAttribute("data-dc-excluir")));
|
||||
} catch (e) {
|
||||
await pidAlert(e.message);
|
||||
}
|
||||
await carregarLista();
|
||||
return;
|
||||
}
|
||||
|
||||
const reprocessarBtn = event.target.closest("[data-dc-reprocessar-abrir]");
|
||||
@ -952,14 +973,18 @@ document.addEventListener("DOMContentLoaded", async () => {
|
||||
document.getElementById("dc-concluida-aviso").hidden = !concluida;
|
||||
document.getElementById("dc-concluir-btn").hidden = concluida;
|
||||
|
||||
dcContasColapsadas = dcColapsoPadrao(apuracao.contas, dcContaNivel);
|
||||
dcDreColapsadas = dcColapsoPadrao(apuracao.linhas_dre, (linha) => Math.max(0, linha.nivel));
|
||||
// Destaque inicial = a última leva já visível de cada ramo (grupo
|
||||
// colapsado por padrão OU folha genuína sem filho nenhum — ver
|
||||
// dcUltimaLevaVisivel()) — nasce destacada sem precisar de nenhum
|
||||
// clique, mesmo ajuste já feito no relatório "Gerar Dashboard" (ver
|
||||
// pidDcrArvore() em dashboard-contabil-relatorio.html), pedido explícito
|
||||
// do usuário pra não abrir a tela inteira na cor de grupo/total.
|
||||
// Padrão de abertura: árvore **inteira expandida**, até a conta analítica
|
||||
// mais funda (pedido explícito do usuário — antes nascia com os grupos
|
||||
// recolhidos por dcColapsoPadrao(), que agora é o que o botão "−" do
|
||||
// cabeçalho aplica sob demanda; ver a seção dos botões mais abaixo).
|
||||
dcContasColapsadas = new Set();
|
||||
dcDreColapsadas = new Set();
|
||||
// Destaque inicial = a última leva já visível de cada ramo (com nada
|
||||
// recolhido, são exatamente as folhas — ver dcUltimaLevaVisivel()) —
|
||||
// nasce destacada sem precisar de nenhum clique, mesmo ajuste já feito no
|
||||
// relatório "Gerar Dashboard" (ver pidDcrArvore() em
|
||||
// dashboard-contabil-relatorio.html), pedido explícito do usuário pra não
|
||||
// abrir a tela inteira na cor de grupo/total.
|
||||
dcContasDestaque = dcUltimaLevaVisivel(apuracao.contas, dcContaNivel, dcContasColapsadas);
|
||||
dcDreDestaque = dcUltimaLevaVisivel(apuracao.linhas_dre, (linha) => Math.max(0, linha.nivel), dcDreColapsadas);
|
||||
dcContasExpandidos = new Set();
|
||||
@ -986,7 +1011,7 @@ document.addEventListener("DOMContentLoaded", async () => {
|
||||
panel.hidden = panel.getAttribute("data-dc-panel") !== "achados";
|
||||
});
|
||||
}
|
||||
dcAvColapsadas = dcColapsoPadrao(apuracao.linhas_analise_vertical, (linha) => Math.max(0, linha.nivel));
|
||||
dcAvColapsadas = new Set(); // mesmo padrão de abertura do Balancete/DRE acima (tudo expandido)
|
||||
dcAvDestaque = dcUltimaLevaVisivel(
|
||||
apuracao.linhas_analise_vertical,
|
||||
(linha) => Math.max(0, linha.nivel),
|
||||
@ -1255,12 +1280,14 @@ document.addEventListener("DOMContentLoaded", async () => {
|
||||
return conta.codigo.split(".").length - 1;
|
||||
}
|
||||
|
||||
// A partir deste nível (equivalente ao 3º segmento do código de
|
||||
// classificação, ex. "1.01.01") o Balancete/DRE nascem recolhidos —
|
||||
// pedido explícito do usuário pra reduzir a poluição visual da árvore
|
||||
// completa; o contador expande sob demanda pra ver o nível analítico
|
||||
// abaixo. Mesmo limiar usado no relatório "Gerar Dashboard"
|
||||
// (_CONTABIL_NIVEL_ABERTO_PADRAO em views.py).
|
||||
// Nível (equivalente ao 3º segmento do código de classificação, ex.
|
||||
// "1.01.01") a partir do qual o botão "−" do cabeçalho recolhe os grupos —
|
||||
// a visão compacta, só com os totais de cada nível. Até uma rodada anterior
|
||||
// este era o estado em que as tabelas **nasciam**; hoje elas abrem com tudo
|
||||
// expandido (pedido explícito do usuário, ver renderRevisao) e esta
|
||||
// constante só vale sob demanda. O relatório "Gerar Dashboard" segue com
|
||||
// seu próprio padrão, server-side e inalterado
|
||||
// (_CONTABIL_NIVEL_ABERTO_PADRAO em views.py, mesmo valor).
|
||||
const PID_DC_NIVEL_ABERTO_PADRAO = 2;
|
||||
|
||||
function dcColapsoPadrao(itens, nivelFn) {
|
||||
@ -2240,6 +2267,7 @@ document.addEventListener("DOMContentLoaded", async () => {
|
||||
}
|
||||
});
|
||||
|
||||
dcAtualizaBotaoArvore("balancete", dcContasColapsadas, "do Balancete");
|
||||
renderContasObsResumo();
|
||||
}
|
||||
|
||||
@ -2351,6 +2379,7 @@ document.addEventListener("DOMContentLoaded", async () => {
|
||||
}
|
||||
});
|
||||
|
||||
dcAtualizaBotaoArvore("dre", dcDreColapsadas, "da DRE");
|
||||
renderDreObsResumo();
|
||||
}
|
||||
|
||||
@ -2401,9 +2430,7 @@ document.addEventListener("DOMContentLoaded", async () => {
|
||||
row.innerHTML = `
|
||||
<th>
|
||||
<span class="dc-th-linha dc-th-linha--inicio">
|
||||
<button type="button" class="icon-btn dc-expandir-tudo-btn" data-dc-expandir-tudo="analise-vertical" aria-label="Expandir todas as linhas da Análise Vertical" title="Expandir todas as linhas até o último nível">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><path d="M12 5v14"/><path d="M5 12h14"/></svg>
|
||||
</button>
|
||||
<button type="button" class="icon-btn dc-recolher-grupos-btn" data-dc-recolher-grupos="analise-vertical" aria-label="Recolher os grupos da Análise Vertical" title="Recolher os grupos (mostrar só os totais de cada nível)">${PID_DC_ICON_RECOLHER_ARVORE}</button>
|
||||
Descrição
|
||||
</span>
|
||||
</th>
|
||||
@ -2415,7 +2442,7 @@ document.addEventListener("DOMContentLoaded", async () => {
|
||||
.join("")}
|
||||
<th>
|
||||
<span class="dc-th-linha">Observação
|
||||
<button type="button" class="icon-btn dc-reset-formatacao-btn" data-dc-reset-formatacao="analise-vertical" aria-label="Restaurar formatação padrão da Análise Vertical" title="Restaurar formatação padrão (recolher grupos como no início)">
|
||||
<button type="button" class="icon-btn dc-reset-formatacao-btn" data-dc-reset-formatacao="analise-vertical" aria-label="Restaurar formatação padrão da Análise Vertical" title="Restaurar formatação padrão (tudo expandido, como ao abrir)">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12a9 9 0 1 0 2.64-6.36"/><path d="M3 3v6h6"/></svg>
|
||||
</button>
|
||||
</span>
|
||||
@ -2498,6 +2525,7 @@ document.addEventListener("DOMContentLoaded", async () => {
|
||||
}
|
||||
});
|
||||
|
||||
dcAtualizaBotaoArvore("analise-vertical", dcAvColapsadas, "da Análise Vertical");
|
||||
renderAnaliseVerticalObsResumo();
|
||||
}
|
||||
|
||||
@ -2633,33 +2661,58 @@ document.addEventListener("DOMContentLoaded", async () => {
|
||||
if (tab === "dashboard") await renderDashboardTab();
|
||||
});
|
||||
|
||||
// ---- Cabeçalho: "Expandir tudo" e "Restaurar formatação padrão" ----
|
||||
// Dois botões por tabela, em pontas opostas da linha de cabeçalho: "+" na
|
||||
// primeira coluna abre a árvore inteira (nada recolhido, até a conta
|
||||
// analítica mais funda), e o de restaurar, na coluna "Observação", descarta
|
||||
// todo expandir/recolher manual e recalcula o mesmo estado inicial de
|
||||
// dcColapsoPadrao()/dcUltimaLevaVisivel() usado quando a apuração é aberta
|
||||
// (ver renderRevisao) — é o caminho de volta do "+", já que ele não é um
|
||||
// toggle. Cada árvore (Balancete/DRE/Análise Vertical) tem o seu par,
|
||||
// porque cada uma tem seu próprio estado de colapso/destaque.
|
||||
// ---- Cabeçalho: toggle da árvore e "Restaurar formatação padrão" ----
|
||||
// Dois botões por tabela, em pontas opostas da linha de cabeçalho. O padrão
|
||||
// de abertura é a árvore **inteira expandida** (ver renderRevisao), e o botão
|
||||
// da primeira coluna é um **toggle** entre esse padrão e a visão compacta de
|
||||
// dcColapsoPadrao() (só os totais de cada nível):
|
||||
//
|
||||
// Expandir tudo zera `dc*Expandidos` junto (não popula com todos os grupos):
|
||||
// com o conjunto vazio o destaque volta a sair de dcUltimaLevaVisivel(), que
|
||||
// sem nada recolhido marca exatamente as folhas — as contas analíticas do
|
||||
// último nível, que é o que interessa destacar com a árvore toda aberta.
|
||||
// Popular `dc*Expandidos` com todos os grupos destacaria quase toda linha da
|
||||
// tabela, o que na prática é o mesmo que não destacar nada (ver
|
||||
// dcDestaqueGrupos acima).
|
||||
// - Mostra "−" e recolhe, enquanto nada estiver recolhido.
|
||||
// - Mostra "+" e volta ao padrão (tudo aberto), assim que houver qualquer
|
||||
// grupo recolhido.
|
||||
//
|
||||
// A face do botão é **derivada** de `colapsadas.size` a cada render (ver
|
||||
// dcAtualizaBotaoArvore), não de um flag próprio — assim ela continua certa
|
||||
// mesmo quando o contador recolhe/expande uma conta pelo toggle da linha, sem
|
||||
// passar por aqui. O botão de restaurar, na coluna "Observação", faz o mesmo
|
||||
// que o "+" (volta ao padrão); ficou redundante quando este virou toggle, e
|
||||
// foi mantido de propósito — é a "borracha" que o usuário já conhece das
|
||||
// outras telas do Portal.
|
||||
//
|
||||
// Cada árvore (Balancete/DRE/Análise Vertical) tem o seu par, porque cada uma
|
||||
// tem seu próprio estado de colapso/destaque.
|
||||
//
|
||||
// Os dois zeram `dc*Expandidos` junto (não populam com todos os grupos): com
|
||||
// o conjunto vazio o destaque volta a sair de dcUltimaLevaVisivel(), que
|
||||
// marca a última leva visível de cada ramo — as folhas, quando nada está
|
||||
// recolhido. Popular `dc*Expandidos` destacaria quase toda linha da tabela, o
|
||||
// que na prática é o mesmo que não destacar nada (ver dcDestaqueGrupos acima).
|
||||
function dcAtualizaBotaoArvore(chave, colapsadas, nomeTabela) {
|
||||
const btn = document.querySelector(`[data-dc-recolher-grupos="${chave}"]`);
|
||||
if (!btn) return;
|
||||
const temGrupoRecolhido = colapsadas.size > 0;
|
||||
btn.innerHTML = temGrupoRecolhido ? PID_DC_ICON_EXPANDIR_ARVORE : PID_DC_ICON_RECOLHER_ARVORE;
|
||||
btn.title = temGrupoRecolhido
|
||||
? "Expandir todos os níveis (padrão desta tela)"
|
||||
: "Recolher os grupos (mostrar só os totais de cada nível)";
|
||||
btn.setAttribute(
|
||||
"aria-label",
|
||||
temGrupoRecolhido ? `Expandir todos os níveis ${nomeTabela}` : `Recolher os grupos ${nomeTabela}`
|
||||
);
|
||||
}
|
||||
|
||||
document.getElementById("dc-contas-thead").addEventListener("click", (event) => {
|
||||
if (event.target.closest("[data-dc-expandir-tudo]")) {
|
||||
dcContasColapsadas = new Set();
|
||||
if (event.target.closest("[data-dc-recolher-grupos]")) {
|
||||
dcContasColapsadas = dcContasColapsadas.size
|
||||
? new Set()
|
||||
: dcColapsoPadrao(apuracaoAtual.contas, dcContaNivel);
|
||||
dcContasExpandidos = new Set();
|
||||
dcContasDestaque = dcUltimaLevaVisivel(apuracaoAtual.contas, dcContaNivel, dcContasColapsadas);
|
||||
renderContas();
|
||||
return;
|
||||
}
|
||||
if (!event.target.closest("[data-dc-reset-formatacao]")) return;
|
||||
dcContasColapsadas = dcColapsoPadrao(apuracaoAtual.contas, dcContaNivel);
|
||||
dcContasColapsadas = new Set();
|
||||
dcContasExpandidos = new Set();
|
||||
dcContasDestaque = dcUltimaLevaVisivel(apuracaoAtual.contas, dcContaNivel, dcContasColapsadas);
|
||||
renderContas();
|
||||
@ -2667,15 +2720,15 @@ document.addEventListener("DOMContentLoaded", async () => {
|
||||
|
||||
document.getElementById("dc-dre-thead").addEventListener("click", (event) => {
|
||||
const nivelFn = (linha) => Math.max(0, linha.nivel);
|
||||
if (event.target.closest("[data-dc-expandir-tudo]")) {
|
||||
dcDreColapsadas = new Set();
|
||||
if (event.target.closest("[data-dc-recolher-grupos]")) {
|
||||
dcDreColapsadas = dcDreColapsadas.size ? new Set() : dcColapsoPadrao(apuracaoAtual.linhas_dre, nivelFn);
|
||||
dcDreExpandidos = new Set();
|
||||
dcDreDestaque = dcUltimaLevaVisivel(apuracaoAtual.linhas_dre, nivelFn, dcDreColapsadas);
|
||||
renderDre();
|
||||
return;
|
||||
}
|
||||
if (!event.target.closest("[data-dc-reset-formatacao]")) return;
|
||||
dcDreColapsadas = dcColapsoPadrao(apuracaoAtual.linhas_dre, nivelFn);
|
||||
dcDreColapsadas = new Set();
|
||||
dcDreExpandidos = new Set();
|
||||
dcDreDestaque = dcUltimaLevaVisivel(apuracaoAtual.linhas_dre, nivelFn, dcDreColapsadas);
|
||||
renderDre();
|
||||
@ -2683,15 +2736,17 @@ document.addEventListener("DOMContentLoaded", async () => {
|
||||
|
||||
document.getElementById("dc-av-thead").addEventListener("click", (event) => {
|
||||
const nivelFn = (linha) => Math.max(0, linha.nivel);
|
||||
if (event.target.closest("[data-dc-expandir-tudo]")) {
|
||||
dcAvColapsadas = new Set();
|
||||
if (event.target.closest("[data-dc-recolher-grupos]")) {
|
||||
dcAvColapsadas = dcAvColapsadas.size
|
||||
? new Set()
|
||||
: dcColapsoPadrao(apuracaoAtual.linhas_analise_vertical, nivelFn);
|
||||
dcAvExpandidos = new Set();
|
||||
dcAvDestaque = dcUltimaLevaVisivel(apuracaoAtual.linhas_analise_vertical, nivelFn, dcAvColapsadas);
|
||||
renderAnaliseVertical();
|
||||
return;
|
||||
}
|
||||
if (!event.target.closest("[data-dc-reset-formatacao]")) return;
|
||||
dcAvColapsadas = dcColapsoPadrao(apuracaoAtual.linhas_analise_vertical, nivelFn);
|
||||
dcAvColapsadas = new Set();
|
||||
dcAvExpandidos = new Set();
|
||||
dcAvDestaque = dcUltimaLevaVisivel(apuracaoAtual.linhas_analise_vertical, nivelFn, dcAvColapsadas);
|
||||
renderAnaliseVertical();
|
||||
|
||||
@ -462,8 +462,8 @@
|
||||
<tr>
|
||||
<th>
|
||||
<span class="dc-th-linha dc-th-linha--inicio">
|
||||
<button type="button" class="icon-btn dc-expandir-tudo-btn" data-dc-expandir-tudo="balancete" aria-label="Expandir todas as contas do Balancete" title="Expandir todas as contas até o último nível">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><path d="M12 5v14"/><path d="M5 12h14"/></svg>
|
||||
<button type="button" class="icon-btn dc-recolher-grupos-btn" data-dc-recolher-grupos="balancete" aria-label="Recolher os grupos do Balancete" title="Recolher os grupos (mostrar só os totais de cada nível)">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><path d="M5 12h14"/></svg>
|
||||
</button>
|
||||
Conta
|
||||
</span>
|
||||
@ -476,7 +476,7 @@
|
||||
<th>Saldo Atual</th>
|
||||
<th>
|
||||
<span class="dc-th-linha">Observação
|
||||
<button type="button" class="icon-btn dc-reset-formatacao-btn" data-dc-reset-formatacao="balancete" aria-label="Restaurar formatação padrão do Balancete" title="Restaurar formatação padrão (recolher grupos como no início)">
|
||||
<button type="button" class="icon-btn dc-reset-formatacao-btn" data-dc-reset-formatacao="balancete" aria-label="Restaurar formatação padrão do Balancete" title="Restaurar formatação padrão (tudo expandido, como ao abrir)">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12a9 9 0 1 0 2.64-6.36"/><path d="M3 3v6h6"/></svg>
|
||||
</button>
|
||||
</span>
|
||||
@ -505,8 +505,8 @@
|
||||
<tr>
|
||||
<th>
|
||||
<span class="dc-th-linha dc-th-linha--inicio">
|
||||
<button type="button" class="icon-btn dc-expandir-tudo-btn" data-dc-expandir-tudo="dre" aria-label="Expandir todas as linhas da DRE" title="Expandir todas as linhas até o último nível">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><path d="M12 5v14"/><path d="M5 12h14"/></svg>
|
||||
<button type="button" class="icon-btn dc-recolher-grupos-btn" data-dc-recolher-grupos="dre" aria-label="Recolher os grupos da DRE" title="Recolher os grupos (mostrar só os totais de cada nível)">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><path d="M5 12h14"/></svg>
|
||||
</button>
|
||||
Descrição
|
||||
</span>
|
||||
@ -514,7 +514,7 @@
|
||||
<th>Valor</th>
|
||||
<th>
|
||||
<span class="dc-th-linha">Observação
|
||||
<button type="button" class="icon-btn dc-reset-formatacao-btn" data-dc-reset-formatacao="dre" aria-label="Restaurar formatação padrão da DRE" title="Restaurar formatação padrão (recolher grupos como no início)">
|
||||
<button type="button" class="icon-btn dc-reset-formatacao-btn" data-dc-reset-formatacao="dre" aria-label="Restaurar formatação padrão da DRE" title="Restaurar formatação padrão (tudo expandido, como ao abrir)">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12a9 9 0 1 0 2.64-6.36"/><path d="M3 3v6h6"/></svg>
|
||||
</button>
|
||||
</span>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user