library(dplyr)
library(stringr)
library(knitr)
# ---------------------------------------------------------------------------
# CAMINHO DAS BASES DE DADOS <-- ajuste aqui se necessário (veja seção acima)
# ---------------------------------------------------------------------------
pasta_dados <- "../dados"
# Monta o caminho completo de um arquivo dentro da pasta de dados.
# Ex.: caminho_dado("despesa_unificada.csv.gz") -> "../dados/despesa_unificada.csv.gz"
caminho_dado <- function(arquivo) file.path(pasta_dados, arquivo)
ler_csv_gz <- function(caminho) {
df <- read.csv(gzfile(caminho), check.names = FALSE, stringsAsFactors = FALSE)
Encoding(names(df)) <- "UTF-8"
df
}
# Seleciona uma coluna pelo NOME. Normaliza acentos, espaços extras e
# caracteres invisíveis (BOM) que costumam vir no cabeçalho exportado — assim
# a leitura é legível e ao mesmo tempo tolerante a variações do arquivo.
# Se o nome não existir, para com mensagem clara em vez de somar a coluna errada.
coluna <- function(dados, nome) {
normalizar <- function(x) {
x <- iconv(x, to = "ASCII//TRANSLIT")
tolower(trimws(gsub("[^A-Za-z0-9]+", " ", x)))
}
i <- match(normalizar(nome), normalizar(names(dados)))
if (is.na(i)) {
stop("Coluna nao encontrada no arquivo: '", nome, "'.\nColunas disponiveis: ",
paste(names(dados), collapse = " | "), call. = FALSE)
}
dados[[i]]
}
em_mil <- function(reais) {
format(round(reais / 1000), big.mark = ".", decimal.mark = ",", scientific = FALSE)
}
# A "fonte" vem com 4 dígitos; comparamos pelos 3 últimos.
fonte_3digitos <- function(x) str_sub(str_pad(as.character(x), 4, pad = "0"), -3, -1)RGF Anexo 1 - Despesa com Pessoal (Consolidado)
Material Suplementar - Documento Quarto Executável
Sobre este documento
Este é um documento Quarto executável: o mesmo arquivo que gera o relatório contém o código que produz os resultados. Faz parte de um projeto experimental / piloto de transparência fiscal.
A Despesa com Pessoal é um dos cálculos mais detalhados da Lei de Responsabilidade Fiscal, com várias regras de inclusão e exclusão. A intenção deste documento é abrir cada regra e explicá-la em linguagem natural, para que a área de contabilidade reconheça os critérios do Manual de Demonstrativos Fiscais (MDF-STN) e do art. 19–20 da LRF.
Para reproduzir: instale R e Quarto, coloque o arquivo de dados na mesma pasta e rode quarto render rgf_a01_pessoal.qmd.
O que este demonstrativo mede
O RGF Anexo 1 apura a Despesa Total com Pessoal (DTP) — a base para verificar se a União respeita o limite da LRF (que é um percentual da RCL). A lógica geral é:
DTP Líquida = Despesa Bruta com Pessoal − Despesas Não Computadas
Ou seja: somamos tudo que é pessoal (vencimentos, encargos, aposentadorias, pensões, terceirização) e depois subtraímos as parcelas que a própria LRF permite excluir do limite (como certas aposentadorias custeadas por fontes específicas). O resultado — a DTP Líquida — é o número que se compara ao teto legal.
Este cálculo é consolidado (soma dos três Poderes). A abertura por Poder depende de uma segmentação institucional que a base pública do Siga Brasil não fornece; por isso trabalhamos com o total consolidado, que valida exatamente.
Escopo desta prova de conceito: apuramos aqui exclusivamente a despesa liquidada. Os Restos a Pagar Não Processados não entram no cálculo, e não se apresenta a razão DTP/RCL nem a apuração do cumprimento dos limites legais. A justificativa dessa escolha está na seção Nota metodológica, ao final.
Fonte de dados
Os dados vêm do Siga Brasil (Senado Federal): https://www12.senado.leg.br/orcamento/sigabrasil
Arquivo: despesa_unificada.csv.gz
| Coluna no arquivo | Papel no cálculo |
|---|---|
GND (Cod) DESP |
Grupo de Natureza da Despesa. Grupo 1 = Pessoal; grupo 3 = Outras Despesas Correntes (entra só para a terceirização). |
Elemento Despesa (Cod) DESP |
Distingue vencimentos (11), obrigações (13), aposentadorias (01), pensões (03), terceirização (34) etc. |
Sub-elemento Despesa (Cod) DESP |
Detalhe de 8 dígitos (a “natureza detalhada”). Usado para capturar exceções específicas. |
Sub-elemento Despesa DESP |
Nome do sub-elemento — usado para identificar aposentadorias/pensões por palavras-chave. |
Modalidade Aplicação (Cod) DESP |
90 = aplicação direta; 91 = intra-orçamentária. Separa casos de obrigações patronais. |
Fonte (Cod) DESP |
Identifica as fontes de recursos que permitem a exclusão de aposentadorias do limite. |
Liquidado (R$) |
O RGF usa a despesa liquidada como métrica. |
Onde estão os dados (leia antes de executar)
Este documento lê os arquivos de dados a partir da pasta dados/ do repositório. Como o .qmd está em standalones/, o caminho padrão é ../dados (a pasta dados que fica um nível acima).
Se você renderizar o documento a partir da própria pasta standalones/, não precisa mudar nada. Se os seus arquivos estiverem em outro lugar, basta ajustar uma única linha no bloco de configuração abaixo — a variável pasta_dados. Exemplos:
- Arquivos na mesma pasta do
.qmd:pasta_dados <- "." - Arquivos em
dados/um nível acima (padrão):pasta_dados <- "../dados" - Um caminho completo no seu computador:
pasta_dados <- "C:/Users/voce/Desktop/dados"(use barras normais/, mesmo no Windows)
Configuração inicial
Listas de referência (critérios do MDF-STN)
Antes de calcular, definimos as listas de códigos que o Manual de Demonstrativos Fiscais estabelece. Nomeamos cada uma para deixar claro o que representa.
# Sub-elementos "ressalvados": despesas que, apesar de estarem no grupo Pessoal,
# NÃO compõem a despesa com pessoal (ex.: sentenças, indenizações específicas).
# São removidas logo na entrada.
ndds_ressalvadas <- c(
"31900503","31900504","31900505","31900506","31900507","31900508",
"31900501","31900502","31900402","31900421","31900819","31900901",
"31900902","31900903","31900904","31900905","31900906","31909209",
"31900809","31900810","31900811","31900812","31900815","31900816"
)
# Naturezas de OBRIGAÇÕES PATRONAIS (encargos do empregador)
nat_obrigacoes <- c("31909213","31919213","31909207")
# Naturezas de APOSENTADORIA (além do elemento 01)
nat_aposentadoria <- c(
"31901702","31909109","31909112","31909115","31909118","31909123",
"31909124","31909128","31909129","31909201","31909403","31909404","31909414"
)
# Naturezas de PENSÕES (além do elemento 03)
nat_pensoes <- c(
"31909110","31909113","31909116","31909119","31909131","31909136",
"31909137","31909130","31909203","31909220","31909221","31909406","31909413"
)
elem_obrigacoes <- c("13","07") # elementos de obrigações patronais
elem_apos_pens <- c("01","03") # aposentadoria e pensão
elem_diversos_inat <- c("05","08","09","17","91","92","94") # elementos que podem conter inativos
# Fontes que permitem EXCLUIR aposentadorias/pensões do limite (art. 19 LRF)
fontes_exclusao <- c("023","024","055","056")
# Palavras que identificam despesa de inativos no nome do sub-elemento
padrao_inativos <- "\\bAPOSENT|\\bINAT|\\bREFORMA|\\bPENS|LEI 7\\.963/1989"Passo 1 — Carregar e preparar a base
Ficamos apenas com os grupos relevantes (1 = Pessoal e 3 = Outras Despesas Correntes, este só para terceirização) e removemos, de saída, os sub-elementos ressalvados.
despesa <- ler_csv_gz(caminho_dado("despesa_unificada.csv.gz"))
d <- data.frame(
grupo = as.character(coluna(despesa, "GND (Cod) DESP")),
elemento = as.character(coluna(despesa, "Elemento Despesa (Cod) DESP")),
subelem = as.character(coluna(despesa, "Sub-elemento Despesa (Cod) DESP")),
subnome = as.character(coluna(despesa, "Sub-elemento Despesa DESP")),
modalidade = as.character(coluna(despesa, "Modalidade Aplicação (Cod) DESP")),
fonte = fonte_3digitos(coluna(despesa, "Fonte (Cod) DESP")),
liquidado = as.numeric(coluna(despesa, "Liquidado (R$)")),
stringsAsFactors = FALSE
)
# Remove os sub-elementos ressalvados e mantém só grupos 1 e 3
d <- d[!d$subelem %in% ndds_ressalvadas & d$grupo %in% c("1","3"), ]
# Atalho: soma o "liquidado" das linhas que satisfazem uma condição
somar_se <- function(condicao) sum(d$liquidado[condicao], na.rm = TRUE)
cat("Linhas de despesa consideradas:", nrow(d), "\n")Linhas de despesa consideradas: 100587
Passo 2 — Despesa Bruta com Pessoal (I)
A despesa bruta soma cinco componentes. Cada um é uma linha do demonstrativo.
11 — Vencimentos e Vantagens
É o “corpo” da folha: tudo do grupo Pessoal que não seja aposentadoria/pensão (01, 03), terceirização (34) ou benefício assistencial (86), e que não caia em uma série de exceções específicas (obrigações patronais destacadas, ressalvas de natureza 0599, nomes de inativos, etc.). Essas exclusões evitam contar duas vezes o que será somado em outras linhas.
# Exclusão A: obrigações patronais que serão contadas na linha 12
exclusao_obrig <-
(substr(d$subelem,1,1)=="3" & d$elemento=="92" &
((d$modalidade=="90" & d$subelem %in% c("31909213","31909207")) |
(d$modalidade=="91" & d$subelem=="31919213"))) |
d$elemento %in% elem_obrigacoes
# Exclusão B: ressalvas específicas de natureza (0599 e um subelemento 92 especial)
exclusao_ressalva <-
(substr(d$subelem,1,1)=="3" & d$elemento=="92" &
d$subelem=="31909205" & d$modalidade %in% c("90","91")) |
str_detect(d$subelem, "0599")
# Exclusão C: qualquer despesa cujo NOME indique inativos (vai para 13/14)
exclusao_inativos <- str_detect(d$subnome, padrao_inativos)
# Exclusão D: elemento 05 com sub-elementos de inativos
exclusao_elem05 <- d$elemento=="05" & str_detect(d$subelem, "0505|0506|0507|0508")
c11 <- d$grupo=="1" &
!d$elemento %in% c("01","03","34","86") &
!exclusao_obrig & !exclusao_ressalva & !exclusao_inativos & !exclusao_elem05
vencimentos <- somar_se(c11)
cat("11 Vencimentos e Vantagens: R$", em_mil(vencimentos), "mil\n")11 Vencimentos e Vantagens: R$ 210.390.865 mil
12 — Obrigações Patronais
Os encargos que o empregador (a União) paga sobre a folha — identificados pelos elementos de obrigações (13, 07) ou pelas naturezas específicas de obrigação patronal.
c12 <- (d$grupo=="1" & d$elemento %in% elem_obrigacoes) |
d$subelem %in% nat_obrigacoes
obrigacoes <- somar_se(c12)
cat("12 Obrigações Patronais: R$", em_mil(obrigacoes), "mil\n")12 Obrigações Patronais: R$ 33.313.510 mil
13 — Aposentadorias e Reformas
Inativos: pelo elemento 01 (ou 86) ou pelas naturezas específicas de aposentadoria.
c13 <- d$grupo=="1" & (d$elemento %in% c("01","86") | d$subelem %in% nat_aposentadoria)
aposentadorias <- somar_se(c13)
cat("13 Aposentadorias e Reformas: R$", em_mil(aposentadorias), "mil\n")13 Aposentadorias e Reformas: R$ 127.518.286 mil
14 — Pensões
Pelo elemento 03 ou pelas naturezas específicas de pensão.
c14 <- d$grupo=="1" & (d$elemento=="03" | d$subelem %in% nat_pensoes)
pensoes <- somar_se(c14)
cat("14 Pensões: R$", em_mil(pensoes), "mil\n")14 Pensões: R$ 58.894.096 mil
16 — Terceirização (substituição de mão de obra)
Contratos que substituem servidores contam como despesa de pessoal, mesmo estando no grupo 3 (Outras Despesas Correntes). É o elemento 34.
c16 <- d$grupo %in% c("1","3") & d$elemento=="34"
terceirizacao <- somar_se(c16)
cat("16 Terceirização: R$", em_mil(terceirizacao), "mil\n")16 Terceirização: R$ 1.007.663 mil
Soma da Despesa Bruta (I)
despesa_bruta <- vencimentos + obrigacoes + aposentadorias + pensoes + terceirizacao
cat("= DESPESA BRUTA (I): R$", em_mil(despesa_bruta), "mil\n")= DESPESA BRUTA (I): R$ 431.124.419 mil
Passo 3 — Despesas Não Computadas (II)
A LRF permite excluir do limite certas despesas — sobretudo aposentadorias e pensões custeadas por fontes específicas (fundos previdenciários próprios), que não devem pesar no teto de pessoal ativo. Identificamos essas parcelas para subtraí-las.
# 21/22/23: elementos 94, 91 e 92 do grupo Pessoal, EXCETO quando são inativos
# custeados pelas fontes de exclusão (esses ficam para a linha 24)
nao_inativo_fonte <- !(d$fonte %in% fontes_exclusao & str_detect(d$subnome, padrao_inativos))
c21 <- d$grupo=="1" & d$elemento=="94" & nao_inativo_fonte
c22 <- d$grupo=="1" & d$elemento=="91" & nao_inativo_fonte
c23 <- d$grupo=="1" & d$elemento=="92" & nao_inativo_fonte
# 24: aposentadorias/pensões custeadas pelas fontes de exclusão (o núcleo da dedução)
c24 <- d$grupo=="1" & d$fonte %in% fontes_exclusao &
(d$elemento %in% elem_apos_pens |
(d$elemento %in% elem_diversos_inat & str_detect(d$subnome, padrao_inativos)))
nao_computadas <- somar_se(c21) + somar_se(c22) + somar_se(c23) + somar_se(c24)
cat("= NÃO COMPUTADAS (II): R$", em_mil(nao_computadas), "mil\n")= NÃO COMPUTADAS (II): R$ 66.924.442 mil
Passo 4 — Despesa Líquida com Pessoal (III)
despesa_liquida <- despesa_bruta - nao_computadas
cat("= DESPESA LÍQUIDA (III): R$", em_mil(despesa_liquida), "mil\n")= DESPESA LÍQUIDA (III): R$ 364.199.978 mil
Demonstrativo completo e validação
demonstrativo <- data.frame(
Item = c(
"11 Vencimentos e Vantagens",
"12 Obrigações Patronais",
"13 Aposentadorias e Reformas",
"14 Pensões",
"16 Terceirização",
"= Despesa Bruta (I)",
"= (-) Não Computadas (II)",
"= Despesa Líquida (III)"
),
`R$ mil` = c(
em_mil(vencimentos), em_mil(obrigacoes), em_mil(aposentadorias),
em_mil(pensoes), em_mil(terceirizacao),
em_mil(despesa_bruta), em_mil(nao_computadas), em_mil(despesa_liquida)
),
check.names = FALSE
)
kable(demonstrativo, align = c("l", "r"))| Item | R$ mil |
|---|---|
| 11 Vencimentos e Vantagens | 210.390.865 |
| 12 Obrigações Patronais | 33.313.510 |
| 13 Aposentadorias e Reformas | 127.518.286 |
| 14 Pensões | 58.894.096 |
| 16 Terceirização | 1.007.663 |
| = Despesa Bruta (I) | 431.124.419 |
| = (-) Não Computadas (II) | 66.924.442 |
| = Despesa Líquida (III) | 364.199.978 |
# ESCOPO: apura somente despesa liquidada. Os Restos a Pagar Não Processados
# existem na base pública, mas exigiriam extração adicional — ficaram fora
# desta prova de conceito. Ver a seção "Nota metodológica", logo abaixo.
oficial_mil <- 364199978 # Despesa liquidada com pessoal — DOU (RGF 3º quadr./2025)
nosso_mil <- round(despesa_liquida / 1000)
diferenca <- nosso_mil - oficial_mil
cat("Nossa Despesa Líquida (somente liquidada): R$", format(nosso_mil, big.mark=".", decimal.mark=","), "mil\n")Nossa Despesa Líquida (somente liquidada): R$ 364.199.978 mil
cat("Oficial (mesma base): R$", format(oficial_mil, big.mark=".", decimal.mark=","), "mil\n")Oficial (mesma base): R$ 364.199.978 mil
cat("Diferença: R$", format(diferenca, big.mark=".", decimal.mark=","), "mil\n\n")Diferença: R$ 0 mil
if (diferenca == 0) {
cat("VALIDADO: coincide com o valor publicado no Diário Oficial (R$ mil).\n")
} else {
cat("Diferença encontrada — investigar.\n")
}VALIDADO: coincide com o valor publicado no Diário Oficial (R$ mil).
Nota metodológica
Este demonstrativo apura exclusivamente a despesa liquidada. Os Restos a Pagar Não Processados estão disponíveis na base pública, mas sua incorporação exigiria uma extração adicional e ampliaria a complexidade desta prova de conceito, cujo objetivo é demonstrar que o demonstrativo é replicável com dados públicos — não reproduzir seu valor integral para fins de apuração de limite.
Pela mesma razão, não se apresenta a relação Despesa Total com Pessoal / Receita Corrente Líquida nem a apuração do cumprimento dos limites dos arts. 19 e 20 da LRF. A comparação acima é apenas de valores, contra a parcela liquidada publicada no Diário Oficial.
A extensão para o valor integral, com os Restos a Pagar Não Processados, é imediata a partir do mesmo pipeline: basta acrescentar a extração correspondente e somá-la às linhas já calculadas — a estrutura de critérios permanece a mesma.
Conclusão
A Despesa com Pessoal consolidada de 2025, na sua parcela liquidada, foi reproduzida a partir de dados exclusivamente públicos e coincide com o valor oficial. Apesar da complexidade das regras — várias inclusões e exclusões previstas na LRF — cada critério está aqui explícito e nomeado, permitindo que qualquer pessoa confira ou questione uma regra específica.
É esse o valor do literate programming para a transparência: a metodologia é texto legível ao lado do código que a executa. E o mesmo vale para os limites do trabalho — o que ficou de fora está dito com todas as letras, no lugar em que o leitor vai procurar.