RREO Anexo 3 - Demonstrativo da Receita Corrente Líquida (RCL)

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 — uma prova de conceito que demonstra a reprodução de demonstrativos oficiais a partir de dados públicos.

A intenção aqui não é só mostrar que os números batem, mas explicar por que cada valor entra ou sai da conta — de forma que alguém da área de contabilidade, mesmo sem experiência em programação, consiga acompanhar cada passo e reconhecer os critérios do Manual de Demonstrativos Fiscais (MDF-STN).

Para reproduzir os resultados:

  1. Instale R e Quarto
  2. Coloque os arquivos de dados (Seção 2) na mesma pasta deste .qmd
  3. Execute: quarto render rreo_a03_rcl.qmd

O que é a Receita Corrente Líquida (RCL)

A RCL é a “régua” da Lei de Responsabilidade Fiscal. Quase todos os limites fiscais da União (gasto com pessoal, dívida, garantias) são expressos como um percentual da RCL. Por isso, calcular a RCL corretamente é o primeiro passo para verificar qualquer um desses limites.

A ideia central é simples, e cabe em uma frase:

RCL = todas as Receitas Correntes, MENOS algumas deduções previstas em lei.

O trabalho todo está em identificar corretamente quais receitas deduzir. A LRF (art. 2º, IV) manda tirar da conta as receitas que, embora arrecadadas, “não são livres” — porque já têm destino certo (previdência, partilha com estados e municípios, PIS/PASEP etc.). Deduzi-las evita contar como “capacidade de gasto” um dinheiro que na prática já está comprometido.

Este documento calcula a RCL em três blocos, seguindo o próprio demonstrativo oficial:

  1. Receita Corrente (I) — o ponto de partida (tudo que é corrente)
  2. Deduções (II) — as parcelas que a lei manda tirar (itens 11 a 15 + transferências constitucionais)
  3. RCL (III) = (I) − (II)

Fontes de dados

Todos os dados vêm do Siga Brasil (Senado Federal), portal público de acesso livre: https://www12.senado.leg.br/orcamento/sigabrasil

Receitas — rcl_receita.csv.gz

Caminho no portal: Painel de Receitas → Arrecadação → Ano 2025 → exportar em Excel (depois comprimido para .csv.gz).

Coluna no arquivo Papel no cálculo
Categoria Econômica (Cod) Receita 1 = Corrente, 2 = Capital. Só a Corrente entra na RCL.
Natureza Receita (Cod) Rec Código de 8 dígitos que identifica o que é a receita (ex.: contribuição previdenciária, PIS/PASEP). É o principal critério das deduções.
Fonte (Cod) Rec Identifica a “bolsa” de onde vem o recurso (ex.: fonte da Seguridade, fonte do Servidor). Usada em conjunto com a natureza.
Arrecadação O valor efetivamente arrecadado (é o que somamos).

Despesas — despesa_unificada.csv.gz

A última dedução (Transferências Constitucionais a estados e municípios) não é uma receita a menos, e sim uma despesa de repasse obrigatório. Por isso ela é medida pelo lado da despesa.

Este demonstrativo usa a mesma base de despesa dos demais — a base unificada do Siga Brasil. Foi verificado que os valores apurados aqui são idênticos, centavo a centavo, aos da extração específica que a RCL usava antes.

Coluna no arquivo Papel no cálculo
Ação (Cod) DESP Identifica as ações de transferência (FPE, FPM, IPI-Exportação etc.).
Programa (Cod) DESP Confirma que a ação pertence ao programa de transferências (0903).
Modalidade Aplicação (Cod) DESP 30–46 = repasse a outro ente (estado/município).
Empenhado (R$) Valor da transferência.
RP Cancelado NProc / Proc (R$) Restos a Pagar cancelados — precisam ser subtraídos, pois foram empenhados mas nunca serão pagos.

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

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("rcl_receita.csv.gz") -> "../dados/rcl_receita.csv.gz"
caminho_dado <- function(arquivo) file.path(pasta_dados, arquivo)

# ---------------------------------------------------------------------------
# Funções auxiliares de leitura e formatação
# ---------------------------------------------------------------------------

# Lê um CSV comprimido (.csv.gz). Marcamos os nomes das colunas como UTF-8
# para que os acentos (ex.: "Categoria Econômica") sejam reconhecidos em
# qualquer sistema operacional.
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]]
}

# Formata um número grande em "R$ mil" com separador de milhar brasileiro.
# Todos os valores do demonstrativo oficial são expressos em R$ mil, então
# dividimos por 1.000 antes de exibir.
em_mil <- function(reais) {
  format(round(reais / 1000), big.mark = ".", decimal.mark = ",", scientific = FALSE)
}

# A "fonte" no Siga Brasil vem com 4 dígitos, mas o código de fonte que
# precisamos comparar tem 3 dígitos (regra de conversão SOF -> Siga).
# Esta função pega sempre os 3 últimos dígitos. Ex.: "1054" -> "054".
fonte_3digitos <- function(x) {
  str_sub(str_pad(as.character(x), 4, pad = "0"), -3, -1)
}

Passo 1 — Receita Corrente (I)

O ponto de partida da RCL é somar toda a receita de categoria econômica “Corrente” (código 1). Nada é filtrado aqui ainda — as exclusões vêm no passo seguinte.

receita <- ler_csv_gz(caminho_dado("rcl_receita.csv.gz"))

# As colunas do arquivo, na ordem em que aparecem, são:
#   1: Categoria Econômica (Cod)   2: Natureza Receita (Cod)
#   3: Fonte (Cod)                 4: Arrecadação
receita <- data.frame(
  cat_economica = as.integer(coluna(receita, "Categoria Econômica (Cod) Receita")),
  natureza      = as.character(coluna(receita, "Natureza Receita (Cod) Rec")),
  fonte         = fonte_3digitos(coluna(receita, "Fonte (Cod) Rec")),
  valor         = as.numeric(coluna(receita, "Arrecadação")),
  stringsAsFactors = FALSE
)
receita <- receita[!is.na(receita$cat_economica), ]   # descarta o total geral

# Atalho: soma o "valor" apenas das linhas que satisfazem uma condição.
# Vamos reutilizar muito esta função nas deduções.
somar_se <- function(condicao) sum(receita$valor[condicao], na.rm = TRUE)

# (I) RECEITA CORRENTE = tudo que é categoria econômica 1 (Corrente)
receita_corrente <- somar_se(receita$cat_economica == 1)

cat("Receita Corrente (I):  R$", em_mil(receita_corrente), "mil\n")
Receita Corrente (I):  R$ 2.981.798.817 mil

Passo 2 — As deduções (II)

Agora identificamos, uma a uma, as parcelas que a lei manda tirar da Receita Corrente. Cada subseção abaixo corresponde a uma linha do demonstrativo oficial. Em todas elas, a lógica é a mesma: somar apenas as receitas correntes que se encaixam em um critério específico.

Dedução 11 — Contribuições para a Seguridade Social (RGPS)

São as contribuições previdenciárias do regime geral (INSS). Elas são arrecadadas pela fonte da Seguridade Social (código de fonte 054). A única exceção são as compensações entre regimes (RGPS↔︎RPPS), que têm tratamento próprio na dedução 13 — por isso as excluímos aqui para não contar em dobro.

fonte_seguridade <- "054"

# Naturezas de compensação previdenciária (entram na dedução 13, não aqui)
nat_compensacao_rpps <- c(
  "19900300","19900310","19900311","19900312","19900313","19900314",
  "19990300","19990301","19990302","19990303","19990304"
)

deducao_11 <- somar_se(
  receita$cat_economica == 1 &
  receita$fonte == fonte_seguridade &
  !receita$natureza %in% nat_compensacao_rpps
)

cat("(-) 11 Contribuições Seguridade:  R$", em_mil(deducao_11), "mil\n")
(-) 11 Contribuições Seguridade:  R$ 708.773.374 mil

Dedução 12 — Contribuição do Servidor (RPPS)

É a contribuição previdenciária dos servidores públicos federais para o seu próprio regime (RPPS). Identificada pelas fontes do Servidor (055 e 056), mais uma natureza específica de contribuição patronal.

fontes_servidor <- c("055", "056")

deducao_12 <- somar_se(
  receita$cat_economica == 1 &
  (receita$fonte %in% fontes_servidor | receita$natureza == "12150116")
)

cat("(-) 12 Contribuição Servidor:  R$", em_mil(deducao_12), "mil\n")
(-) 12 Contribuição Servidor:  R$ 18.982.523 mil

Dedução 13 — Compensação Financeira entre Regimes (RGPS/RPPS)

Quando um trabalhador migra entre o regime geral (INSS) e um regime próprio (servidor), há acerto de contas entre os regimes. Esse valor é uma receita que “só passa pelo caixa” — não é capacidade de gasto — e por isso é deduzida. São exatamente as naturezas de compensação que já havíamos separado na dedução 11.

deducao_13 <- somar_se(
  receita$cat_economica == 1 &
  receita$natureza %in% nat_compensacao_rpps
)

cat("(-) 13 Compensação RGPS/RPPS:  R$", em_mil(deducao_13), "mil\n")
(-) 13 Compensação RGPS/RPPS:  R$ 183.866 mil

Dedução 14 — Contribuição para o Custeio das Pensões Militares

Contribuição específica dos militares para o custeio de suas pensões. Identificada por três “famílias” de natureza de receita, reconhecidas pelos seus dígitos iniciais.

# str_detect com "^" testa se o código COMEÇA com aquele prefixo.
# Ex.: "^1210051" pega qualquer natureza que comece com 1210051.
deducao_14 <- somar_se(
  receita$cat_economica == 1 &
  str_detect(receita$natureza, "^1210051|^1215041|^121911")
)

cat("(-) 14 Pensões Militares:  R$", em_mil(deducao_14), "mil\n")
(-) 14 Pensões Militares:  R$ 9.569.993 mil

Dedução 15 — Contribuição para o PIS/PASEP

Esta é a dedução mais sutil, porque o PIS/PASEP pode aparecer de duas formas na base, e as duas precisam ser capturadas:

  • Pela natureza: receitas cujo código começa com 1210091 ou 1212 são PIS/PASEP — desde que não estejam nas fontes do servidor ou da seguridade (para não invadir as deduções 11 e 12).
  • Pela fonte: receitas na fonte do PIS/PASEP (040/041) que, por algum motivo, não tenham aquela natureza — mesmo assim são PIS/PASEP e entram.

É a clássica situação de “A ou B” — se cair em qualquer um dos dois casos, é PIS/PASEP. Foi provavelmente este o critério mais difícil de entender no código original; o objetivo aqui é deixá-lo explícito.

fontes_pis_pasep <- c("040", "041")

# Caso A: tem a NATUREZA de PIS/PASEP e NÃO está nas fontes servidor/seguridade
eh_pis_por_natureza <-
  str_detect(receita$natureza, "^1210091|^1212") &
  !receita$fonte %in% c(fontes_servidor, fonte_seguridade)

# Caso B: está na FONTE de PIS/PASEP mas NÃO tem a natureza acima
eh_pis_por_fonte <-
  !str_detect(receita$natureza, "^1210091|^1212") &
  receita$fonte %in% fontes_pis_pasep

deducao_15 <- somar_se(
  receita$cat_economica == 1 & (eh_pis_por_natureza | eh_pis_por_fonte)
)

cat("(-) 15 PIS/PASEP:  R$", em_mil(deducao_15), "mil\n")
(-) 15 PIS/PASEP:  R$ 105.896.291 mil

Dedução — Transferências Constitucionais e Legais

Esta é a única dedução medida pelo lado da despesa. São os repasses obrigatórios da União a estados e municípios (FPE, FPM, IPI-Exportação, etc.). Como são despesas de repasse — dinheiro que a União arrecada mas é obrigada a distribuir — reduzem a receita “líquida” disponível.

A conta tem dois cuidados:

  1. Identificar as ações de transferência (lista de códigos do MDF), confirmando que pertencem ao programa de transferências (0903) e usam modalidade de repasse a outro ente (30 a 46). Duas ações (0E36 e 00SB) entram diretamente, sem essas condições.
  2. Subtrair os Restos a Pagar cancelados: valores que foram empenhados em anos anteriores mas cancelados — como nunca serão pagos, não podem contar como transferência.
despesa <- ler_csv_gz(caminho_dado("despesa_unificada.csv.gz"))

despesa <- data.frame(
  acao       = as.character(coluna(despesa, "Ação (Cod) DESP")),
  programa   = str_pad(as.character(coluna(despesa, "Programa (Cod) DESP")), 4, pad = "0"),
  modalidade = as.character(coluna(despesa, "Modalidade Aplicação (Cod) DESP")),
  empenhado  = as.numeric(coluna(despesa, "Empenhado (R$)")),
  # Soma os dois tipos de Restos a Pagar cancelados numa coluna só
  rp_cancelado = as.numeric(coluna(despesa, "RP Cancelado NProc (R$)")) +
                 as.numeric(coluna(despesa, "RP Proc Cancelado (R$)")),
  stringsAsFactors = FALSE
)

# Ações de transferência constitucional/legal (lista do MDF-STN)
acoes_transferencia <- c(
  "0044","0045","0046","0050","0051","00H6","006M","00G6","0169","0223",
  "0369","0546","0547","0999","099B","0A53","0C03","0C33","0E25","0E36",
  "00PX","00QR","00S3","00S7","00S8","00SE","00RX","00UH"
)
modalidades_repasse <- c("30","31","32","35","36","40","41","42","45","46")

# Uma linha de despesa é "transferência" se:
#   - é uma ação da lista, no programa 0903, com modalidade de repasse
#   OU
#   - é uma das duas ações que entram diretamente (0E36, 00SB)
eh_transferencia <-
  (despesa$acao %in% acoes_transferencia &
   despesa$modalidade %in% modalidades_repasse &
   despesa$programa == "0903") |
  despesa$acao %in% c("0E36", "00SB")

# Transferência líquida = empenhado - restos a pagar cancelados
transferencias <-
  sum(despesa$empenhado[eh_transferencia],   na.rm = TRUE) -
  sum(despesa$rp_cancelado[eh_transferencia], na.rm = TRUE)

cat("(-) Transferências Constitucionais:  R$", em_mil(transferencias), "mil\n")
(-) Transferências Constitucionais:  R$ 620.657.272 mil

Total das deduções (II)

deducoes <- deducao_11 + deducao_12 + deducao_13 +
            deducao_14 + deducao_15 + transferencias

cat("= DEDUÇÕES (II):  R$", em_mil(deducoes), "mil\n")
= DEDUÇÕES (II):  R$ 1.464.063.320 mil

Passo 3 — Receita Corrente Líquida (III)

rcl <- receita_corrente - deducoes

cat("= RCL (III):  R$", em_mil(rcl), "mil\n")
= RCL (III):  R$ 1.517.735.497 mil

Demonstrativo completo e validação

Reunimos todas as linhas no formato do demonstrativo oficial e comparamos com o valor publicado no Diário Oficial (RREO de Dezembro/2025).

demonstrativo <- data.frame(
  Item = c(
    "Receita Corrente (I)",
    "(-) 11 Contribuições Seguridade",
    "(-) 12 Contribuição Servidor",
    "(-) 13 Compensação RGPS/RPPS",
    "(-) 14 Pensões Militares",
    "(-) 15 PIS/PASEP",
    "(-) Transferências Constitucionais",
    "= Deduções (II)",
    "= RCL (III)"
  ),
  `R$ mil` = c(
    em_mil(receita_corrente),
    em_mil(deducao_11), em_mil(deducao_12), em_mil(deducao_13),
    em_mil(deducao_14), em_mil(deducao_15), em_mil(transferencias),
    em_mil(deducoes), em_mil(rcl)
  ),
  check.names = FALSE
)

kable(demonstrativo, align = c("l", "r"))
Item R$ mil
Receita Corrente (I) 2.981.798.817
(-) 11 Contribuições Seguridade 708.773.374
(-) 12 Contribuição Servidor 18.982.523
(-) 13 Compensação RGPS/RPPS 183.866
(-) 14 Pensões Militares 9.569.993
(-) 15 PIS/PASEP 105.896.291
(-) Transferências Constitucionais 620.657.272
= Deduções (II) 1.464.063.320
= RCL (III) 1.517.735.497
rcl_oficial_mil <- 1517735497   # valor publicado no DOU (Dez/2025)
nosso_rcl_mil   <- round(rcl / 1000)
diferenca       <- nosso_rcl_mil - rcl_oficial_mil

cat("Nossa RCL:  R$", format(nosso_rcl_mil,   big.mark=".", decimal.mark=","), "mil\n")
Nossa RCL:  R$ 1.517.735.497 mil
cat("RCL oficial:  R$", format(rcl_oficial_mil, big.mark=".", decimal.mark=","), "mil\n")
RCL oficial:  R$ 1.517.735.497 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).

Conclusão

A RCL de 2025 foi reproduzida a partir de dados exclusivamente públicos do Siga Brasil, seguindo os critérios do Manual de Demonstrativos Fiscais. Cada dedução foi calculada e explicada isoladamente, e o resultado final coincide com o valor oficial publicado no Diário Oficial.

O ponto central para a área de contabilidade: cada número deste demonstrativo pode ser rastreado até uma regra explícita, e cada regra está escrita aqui em linguagem natural ao lado do código que a executa. Qualquer pessoa pode conferir, questionar ou adaptar um critério — que é justamente o que o literate programming busca oferecer à transparência fiscal.