Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

🧮 Dispêndio

Controle do limite de contratação direta por valor (art. 75, I e II, da Lei 14.133/2021) — por ramo de atividade, unidade gestora e exercício, com a declaração que protege quem assina.

Licença: Apache 2.0 Docs: CC BY 4.0 Estado: em produção em um município Procuram-se parceiros

A Lei 14.133 permite contratar sem licitação até um teto anual por valor. O § 1º do art. 75 diz como esse teto se mede: somando tudo o que a unidade gestora gastou no exercício com objetos de mesma natureza. É a regra anti-fracionamento — e é a que quase nenhum município consegue aplicar, porque exige saber, a cada nova compra, quanto daquele ramo já foi comprometido e quanto já foi pago.

Na prática o controle vive numa planilha por setor, alimentada à mão, que ninguém consegue somar. Quem assina a declaração de que o limite não foi ultrapassado assina sem ter como saber.

Este repositório é o sistema que faz essa conta — e é público porque essa dor é a de todo município que compra por dispensa.


📌 Sumário


🎯 Por que isso importa (e por que não é só nosso)

A dor O que acontece na prática
O teto é anual, mas a compra é pontual Cada dispensa parece pequena. O estouro só aparece quando alguém soma o ano inteiro — geralmente o controle externo.
"Mesma natureza" não tem régua Sem um critério fixo para agrupar objetos, cada setor decide sozinho o que soma com o quê.
Comprometido não é o mesmo que pago A requisição de compra bloqueia dotação antes do empenho. Um controle que só olha empenhos vê o estouro tarde demais.
A declaração é assinada às cegas O § 3º do art. 75 exige divulgar; o processo pede uma declaração de que o limite foi respeitado. Sem a soma, ela é um ato de fé.

A base normativa

  • Lei 14.133/2021, art. 75, I e II — dispensa por valor para obras/engenharia (I) e demais compras e serviços (II); tetos atualizados anualmente por decreto federal (art. 182). Valores de 2026: R$ 130.984,20 e R$ 65.492,11 (Decreto 12.807/2025).
  • Art. 75, § 1º — os limites consideram o somatório do exercício, por unidade gestora, de objetos de mesma natureza.
  • Art. 75, § 7º — manutenção de veículos até um sublimite não consome o teto do inciso I (R$ 10.478,74 em 2026).
  • O que é "mesma natureza" fica para cada ente. No município de origem, o Decreto 19.637/2024, art. 7º, fixou ramo de atividade = subclasse CNAE, por unidade gestora. A União e o Estado de São Paulo caminham para catálogo de materiais. O sistema nasceu com CNAE, mas o critério é uma camada trocável (ver o que você vai precisar trocar).

O custo da inação

Fracionamento é o apontamento mais comum de tribunais de contas em compras diretas. A consequência não é só a glosa: é a responsabilização pessoal de quem autorizou e de quem assinou a declaração. Um controle que mostra o saldo do ramo antes da contratação transforma esse risco individual em processo.


⚙️ Como funciona

exports CSV do sistema de compras          base CNAE do IBGE (1.332 subclasses)
 (catálogo · SD · RC · AF · empenho)                    │
              │                                         │
              ▼                                         ▼
     importação com prévia  ──►  bancada de classificação item → subclasse CNAE
              │                                         │
              ▼                                         ▼
   motor de saldo:  UG × exercício × subclasse CNAE × inciso
        realizado (empenhos) + comprometido (RCs abertas com SD) vs. teto
              │
              ├──► painel da UG: faixas ≥ 80 % atenção · ≥ 90 % crítico · ≥ 100 % estourado
              ├──► painel central: todas as UGs, ranking dos ramos, montante não classificado
              └──► Declaração de Limite de Dispêndio (PDF, numerada, imutável) — recusada se a compra estoura o ramo
  1. Importar. O administrador sobe os CSVs exportados do sistema de compras. Antes de gravar, o sistema mostra o que é novo, o que atualiza e o que rejeita (com motivo). Reimportar o mesmo arquivo não duplica nada.
  2. Classificar. Itens de catálogo sem ramo entram numa fila ordenada pelo valor envolvido. O curador escolhe a subclasse CNAE com busca na base do IBGE; o inciso (I ou II) é derivado da subclasse e pode ser sobrescrito com registro.
  3. Calcular. Para cada UG, exercício, subclasse e inciso: realizado (empenhos, líquidos de anulação) + comprometido (requisições abertas com solicitação de demanda vinculada, abatidas do que já foi empenhado). O que não tem classificação não some: aparece como montante não classificado, sempre visível.
  4. Alertar. Painéis por UG e consolidado, com faixas de alerta e detecção de requisições "mistas" (itens de ramos diferentes).
  5. Declarar. O coordenador da UG escolhe uma requisição e emite a declaração em PDF: ramo, teto, realizado, comprometido, valor da compra, saldo antes e depois, data/hora e emissor. É uma fotografia do saldo naquele instante, numerada e imutável. Se a compra estoura o ramo, a declaração não sai — o sistema não gera atestado falso; registra a tentativa.
  6. Conferir o fornecedor. Na importação de autorizações de fornecimento, o CNPJ é consultado na BrasilAPI e o sistema avisa se o ramo da compra não está entre as atividades do contratado. Consultivo: nunca bloqueia.

Três papéis, sem senha própria: Administrador/Curador (importa, classifica, gerencia papéis e tetos), Coordenador de UG (vê a sua UG e emite declarações) e Visão Central (lê todas as UGs). Quem diz quem é você é o SSO do órgão — o sistema só diz o que você pode.


🔍 Estado real do projeto

Esta seção existe porque vitrine sem honestidade não serve para ninguém. Se você está avaliando adotar este projeto, precisa saber exatamente onde ele está — inclusive o que ainda não existe.

Componente Estado Observação
Importação dos cinco tipos de CSV, com prévia, idempotência e log Funciona Layouts em dispendio/data/layouts_admc.json, ajustáveis sem código; o da RC foi fixado com export real
Base CNAE do IBGE (1.332 subclasses, hierarquia, notas) Funciona Versionada no repositório; scripts/baixar_cnae.py atualiza
Bancada de classificação item → CNAE, com histórico Funciona Busca textual nas descrições e notas explicativas
Motor de saldo (realizado + comprometido, faixas, § 7º, não classificado, RC mista) Funciona Camada pura, sem web nem banco, coberta por testes
Painéis da UG e central Funciona < 2 s com um exercício completo carregado (testado com massa de 50 mil linhas)
Declaração de Limite de Dispêndio em PDF, numerada e imutável Funciona Recusa quando a compra estoura o ramo; registra a tentativa
Checagem consultiva de CNPJ (BrasilAPI, cache de 30 dias) Funciona Indisponibilidade da API não trava nada; checagens ficam pendentes e reprocessáveis
Papéis e segregação por UG impostos no backend Funciona Nenhum cabeçalho HTTP vale como identidade
Uso em produção Em uso Em uma secretaria do município de origem, com exports reais
Identidade (SSO) 🟡 Só simulada nesta versão O provedor de produção depende do portal interno do município e não acompanha o repositório; aqui a identidade é escolhida em tela e o servidor só atende em 127.0.0.1. O contrato para plugar o seu SSO está em dispendio/web/identidade.py
Modelo oficial da declaração 🟡 Layout provisório O PDF tem todos os dados; o desenho conforme o modelo oficial do órgão é o próximo incremento
Adaptador para outro sistema de compras Não existe Só o layout do ERP de origem. Outro ERP = outro JSON de layout — nunca foi feito
Critério de ramo por catálogo (em vez de CNAE) Não existe Direção registrada; a camada de classificação é a única que mudaria
Sugestão automática de CNAE (IA) Não existe Especificada em Onde entra a IA

🚧 O gargalo, dito com todas as letras

O sistema depende de exports manuais do sistema de compras. Funciona — mas cada rodada de importação é um servidor exportando CSVs. Integração direta (API ou leitura de banco) depende do fornecedor do ERP de cada órgão, e é o que separa "controle semanal" de "controle no momento da compra".


🧠 Onde entra a Inteligência Artificial

Sejamos precisos: hoje este projeto não tem IA nenhuma. É importação, classificação humana e aritmética.

Ele importa para uma agenda de IA no setor público por outro motivo: não existe base de dados de dispêndio por ramo em município nenhum — existem planilhas. Este sistema cria essa base (documento × item × subclasse CNAE × valor × exercício, com a decisão de classificação registrada e datada), e é ela que torna possíveis as aplicações abaixo. A fila de classificação é, literalmente, um conjunto de treinamento sendo rotulado por um curador.

Aplicação Problema real Entrada → Saída Métrica
Sugestão de subclasse CNAE A classificação é o trabalho humano mais caro do sistema: ler a descrição do item e achar a subclasse certa entre 1.332. Hoje é busca textual + julgamento descrição do item + histórico de classificações → 3 subclasses candidatas com confiança % de sugestões aceitas sem edição pelo curador
Detecção de fracionamento por similaridade Objetos "de mesma natureza" com descrições diferentes (TONER HP 85A e CARTUCHO DE TONER PARA LASERJET) escapam de qualquer regra por código itens comprometidos no exercício → grupos de objetos equivalentes que somados se aproximam do teto fracionamentos apontados pelo sistema × apontados por auditoria
Referência de preço O sistema sabe quanto se gasta por ramo, não se o preço é bom. O Colibri (MGI) tem 27 mi de itens de NF-e federais com NCM item + valor unitário → mediana federal do NCM correspondente, via tradutor CATMAT→NCM desvio do preço pago em relação à mediana
Conferência espelho O que o município publica no PNCP deveria bater com a base interna de modalidade 8 base interna × PNCP → divergências documentadas apontamentos evitados

Nenhuma delas está implementada. Estão aqui como roadmap e convite. A primeira é a mais barata e a que mais economiza tempo humano; a segunda é a que mais interessa a controle interno.


🔧 Reproduza no seu município

Comece sem nada

git clone https://github.com/maia-andre/dispendio.git && cd dispendio
python -m venv .venv && source .venv/bin/activate       # Windows: .venv\Scripts\activate
pip install -e ".[dev]"
python scripts/gerar_demo.py demo.sqlite3                # base sintética: 6 UGs, cenários de atenção/crítico/estouro, fila, fornecedores
python -m dispendio --banco demo.sqlite3                 # http://127.0.0.1:8001/

Abra http://127.0.0.1:8001/simulacao e escolha quem você é: ana.admin (administrador), vera.central (visão central) ou um coordenador (carlos.sec, dora.sms, joao.smc…). A base de demonstração é inteiramente sintética — os CNPJs têm dígito verificador inválido de propósito.

Para começar do zero com os seus dados:

python -m dispendio --banco dispendio.sqlite3 criar-admin seu.login --nome "Seu Nome"   # primeiro administrador
python -m dispendio --banco dispendio.sqlite3                                            # cadastre as UGs e importe os CSVs pela tela de Administração
python -m dispendio --banco dispendio.sqlite3 saldos --ug SEC --exercicio 2026           # saldos de uma UG na linha de comando
pytest                                                                                   # suíte completa (~650 testes, < 30 s)

Todos os dados ficam num único arquivo SQLite; backup = copiar o arquivo. Os CSVs em exemplos/ mostram o layout esperado de cada tipo.

O que você vai precisar trocar

O que Como está aqui O que fazer no seu órgão
Identidade simulada, escolhida em tela, só 127.0.0.1 Implemente ProvedorIdentidade.identificar() em dispendio/web/identidade.py lendo a sessão do seu SSO (cookie do portal, JWT, cabeçalho de proxy autenticador) e devolvendo uma Identidade. Papéis e segregação por UG não mudam
Layout dos CSVs os do ERP de origem, em dispendio/data/layouts_admc.json Outro sistema de compras = outro JSON (nomes de colunas e apelidos aceitos), sem tocar em código: DISPENDIO_LAYOUTS=/caminho/seu.json
Tetos 2026 pré-carregados (Decreto 12.807/2025) Tela Administração → Tetos: por exercício e inciso, mais o sublimite do § 7º
Critério de ramo subclasse CNAE (Decreto municipal 19.637/2024) Se o seu ente usa catálogo de materiais, a camada a trocar é dispendio/core/classificacao.py + a base de referência; o motor de saldo não sabe o que é um ramo, só agrega por chave
Brasão e nome do órgão placeholder em dispendio/web/static/brasao.svg e cabeçalho em templates/base.html Substitua o arquivo e o texto

Ambiente de referência

Python 3.11+, Flask 3, SQLite, waitress como servidor. Sem nuvem, sem banco externo, sem serviço pago. Únicos serviços externos: API do IBGE (só para atualizar a base CNAE, opcional) e BrasilAPI (consulta pública de CNPJ; se cair, nada trava). Nenhum dado interno do órgão sai da máquina além do CNPJ consultado. Roda numa estação Windows ou Linux comum.


🗺️ Roadmap

  • Desenho do PDF da declaração conforme o modelo oficial do órgão
  • Provedor de identidade genérico (JWT/OIDC) para servir de exemplo de integração com SSO
  • Sugestão automática de subclasse CNAE na bancada de classificação
  • Segundo adaptador de importação (outro ERP municipal) — precisa de parceiro
  • Módulo de inteligência de preços sobre o Colibri (mediana por NCM, tradutor CATMAT→NCM)
  • Conferência espelho com o PNCP

🤝 Procuram-se parceiros

  • Um município com outro sistema de compras. Para provar que o adaptador de importação é mesmo um JSON, e não uma promessa. Se você exporta SDs/RCs/AFs/empenhos em CSV de qualquer ERP, dá para testar em uma tarde.
  • Quem usa catálogo de materiais como critério de "mesma natureza". Para desenhar a segunda camada de classificação com um caso real.
  • Controle interno ou tribunal de contas. Para validar se a régua do § 1º está certa e se a declaração tem o que uma auditoria pede.
  • Quem já plugou um sistema Flask num SSO institucional. O provedor de identidade genérico está aberto.

Veja CONTRIBUTING.md — não precisa escrever código.


🏛️ Contexto institucional

Desenvolvido no Departamento de Planejamento e Gestão de Recursos (DPGR) da Prefeitura de São José dos Campos - SP, a partir da necessidade concreta de substituir o controle manual do limite de dispensa por valor, que não resistia à regra anti-fracionamento do § 1º do art. 75.

O projeto nasceu de iniciativa própria do departamento, com recurso mínimo, e é publicado no espírito do BBSIA — Banco Brasileiro de Soluções de IA para a Gestão Pública (ENAP/LIIA): compartilhar soluções organizadas pelo problema que resolvem, para que órgãos públicos parem de reconstruir isoladamente o que já existe.

Faz parte de uma família de soluções do mesmo departamento sobre o ciclo da compra pública: Patrimônio Inteligente (inventário patrimonial com RFID). Outras — notas fiscais na SEFAZ, expedição de almoxarifado, fiscalização de contratos, termos de referência — estão a caminho.

Este repositório é uma versão pública derivada do sistema em uso; o desenvolvimento do dia a dia acontece no repositório interno do município, e as mudanças são trazidas para cá em blocos.


📜 Licença

Código: Apache License 2.0 — uso, modificação e redistribuição livres, inclusive para fins comerciais, com concessão expressa de patente e exigência de atribuição.

Documentação: CC BY 4.0.

Escolhemos uma licença permissiva deliberadamente: o objetivo é remover atrito de adoção. Um jurídico municipal aprova Apache 2.0 sem discussão, e um fornecedor consegue integrar este código ao sistema de compras já contratado pela sua prefeitura sem conflito de licença. Copyleft protegeria melhor contra apropriação, mas ao custo de reduzir exatamente o alcance que buscamos.

⚖️ Titularidade: nos termos do art. 4º da Lei nº 9.609/1998, os direitos sobre software desenvolvido por servidor no exercício da função pertencem, em regra, ao ente empregador. A formalização da autorização institucional de publicação está em curso — veja o arquivo NOTICE para os detalhes.


Se o seu município também controla o teto de dispensa numa planilha que ninguém consegue somar, este repositório é seu.

A conta do § 1º é simples. O difícil é ter os dados para fazê-la — e é isso que este sistema constrói.

About

Controle do limite de contratação direta por valor (art. 75, I e II, Lei 14.133/2021) por ramo de atividade, com a declaração que protege quem assina

Topics

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages