Biblioteca para automatização web nos sistemas do Tesouro do Estado do Rio de Janeiro
Project description
🪐 jupiter-subtes
jupiter-subtes é uma biblioteca Python publicada no PyPI para automatizar tarefas rotineiras do setor contábil do Tesouro do Estado do Rio de Janeiro. Ela unifica, em um único pacote, três domínios de automação: o sistema contábil SIAFE-Rio2, o sistema de documentos SEI e a integração com o ecossistema Microsoft 365 (SharePoint e Graph API).
pip install jupiter-subtes
Visão Geral dos Módulos
| Módulo | Classe principal | Domínio |
|---|---|---|
siafelibrary |
Siafe |
Automação web do SIAFE-Rio2 (GR, PDE, PDT, NP, NA, EV) |
seilibrary |
SEI |
Automação web do SEI (processos, documentos, despachos) |
apipoint |
SharePoint, GraphAPI |
SharePoint (arquivos/pastas) e Microsoft Graph API |
from jupiter import Siafe, SEI, SharePoint, GraphAPI
1. siafelibrary — Automação do SIAFE
A classe Siafe encapsula toda a interação com o SIAFE-Rio2. Ela gerencia o navegador automaticamente (herda de automaweb.Navegador) e expõe métodos de alto nível para login, geração de documentos em lote e consultas.
Documentos suportados
| Método | Tipo de documento |
|---|---|
gerar_GR |
Guia de Recolhimento (orçamentária e extra-orçamentária) |
gerar_PDE |
Programação de Desembolso Extra-orçamentária |
gerar_PDT |
Programação de Desembolso de Transferência |
gerar_NP |
Nota Patrimonial |
gerar_NA |
Nota de Aplicação e Resgate |
gerar_EV |
Nota de Evento |
Exemplo completo: geração de GRs em lote
import pandas as pd
from jupiter import Siafe
# 1. DataFrame com os lançamentos pendentes
# Colunas obrigatórias: id, data, valor, observacao, tipo_id
# Colunas preenchidas pelo robô: num_documento, tempo_contab
df = pd.DataFrame([
{"id": 1, "data": "01/07/2025", "valor": 1500.00,
"observacao": "Recolhimento referente a julho/2025",
"tipo_id": "GR_FUNDO_A", "num_documento": None, "tempo_contab": None},
{"id": 2, "data": "01/07/2025", "valor": 3200.50,
"observacao": "Recolhimento referente a julho/2025",
"tipo_id": "GR_FUNDO_B", "num_documento": None, "tempo_contab": None},
])
# 2. Dicionário de regras contábeis (um por tipo_id)
regras = {
"GR_FUNDO_A": {
"TipoDocumento": "01 - Arrecadação",
"UG": "123456",
"DomicilioBancario": "0001",
"DomicilioBancarioCompleto":"0001 - BANCO DO BRASIL S.A.",
"ExtraOrcamentario": False,
"IEF": "1",
"Fonte": "100",
"FonteRJ": "100",
"TipoDetalhamentoFonte": "0",
"DetalhamentoFonte": "0000",
"Convenio": "99999",
"TipoPatrimonial": "Ativo",
"ItemPatrimonial": "Bancos Conta Movimento",
"OperacaoPatrimonial": "Entrada de Recursos",
"NaturezaReceita": "11180111",
},
"GR_FUNDO_B": {
# ... mesma estrutura, campos diferentes
},
}
# 3. Callback chamado a cada documento gerado com sucesso
def ao_contabilizar(id, num_documento, tempo_contab):
print(f"[OK] id={id} doc={num_documento} tempo={tempo_contab}s")
# Aqui você pode salvar no banco de dados, enviar e-mail, etc.
# 4. Execução
siafe = Siafe()
if siafe.logar_siafe(versaoSiafe=1, usuario="12345678900", senha="senha"):
siafe.gerar_documento(
funcao=siafe.gerar_GR,
df=df,
dict_map=regras,
callback_sucesso=ao_contabilizar,
)
Exemplo: login e consulta via API REST
from jupiter import Siafe
siafe = Siafe()
siafe.logar_siafe_API(versaoSiafe=1, usuario="12345678900", senha="senha")
# Consulta um relatório do FlexVision pelo ID
df_resultado = siafe.consulta_flexvision(
id="12345",
parametros_consulta="2025,123456" # parâmetros separados por vírgula
)
print(df_resultado.head())
Exemplo: consultar e imprimir GRs por número
# Após gerar_documento, df['num_documento'] já está preenchido.
# Este método abre cada GR no SIAFE e salva o PDF automaticamente.
siafe.consultar_GR_numDoc(df=df, callback_sucesso=lambda id: print(f"PDF gerado para id={id}"))
Ambientes disponíveis (versaoSiafe)
| Valor | Ambiente |
|---|---|
1 |
Produção |
2 |
Beta / Testes |
3 |
Homologação |
4 |
SIAFE-Rio 1 (legado) |
2. seilibrary — Automação do SEI
A classe SEI automatiza o Sistema Eletrônico de Informações (SEI). Ela também herda de automaweb.Navegador e oferece métodos para navegar em processos, analisar documentos, incluir despachos e gerenciar blocos de assinatura.
Exemplo: controle de processos da unidade
from jupiter import SEI
sei = SEI()
sei.logar_sei(usuario="joao.silva", senha="senha", orgao="SEFAZ")
sei.trocar_unidade("SUPCONC")
# Retorna todos os processos visíveis no Controle de Processos
# com todas as colunas (tipo, atribuicao, marcadores, prazo, etc.)
processos = sei.controlar_processos()
for p in processos:
print(p["processo"], "|", p["tipo"], "|", p["marcadores"])
Exemplo: filtrar processos por marcador e incluir despacho
from jupiter import SEI
sei = SEI()
sei.logar_sei(usuario="joao.silva", senha="senha", orgao="SEFAZ")
# Obtém os processos da visualização por marcador
todos = sei.visualizar_processos_por_marcador(marcador="Aguardando Despacho")
# Filtra apenas os que têm o marcador desejado
pendentes = sei.filtrar_processos_por_marcador(todos, marcador="Aguardando Despacho")
for numero in pendentes:
sei.pesquisar_processo(numero)
sei.expandir_pastas()
# Analisa os documentos do processo
documentos = sei.analisar_documentos(condicao="Memorando")
# Verifica se algum memorando menciona os termos relevantes
encontrados = sei.verificar_despacho(documentos, termos_busca=["aprovado", "autorizado"])
if encontrados:
# Cria um despacho de encaminhamento
criado = sei.incluir_despacho(texto_padrao="Encaminhamento Padrão SUPCONC")
if criado:
sei.incluir_processo_bloco(bloco="Bloco Assinatura Mensal")
Exemplo: análise detalhada de documentos
sei.pesquisar_processo("0012345-67.2025.8.19.0000")
sei.expandir_pastas()
documentos = sei.analisar_documentos()
# verificar_despacho → OR (qualquer um dos termos)
# verificar_despacho_estrito → AND (todos os termos)
# verificar_despacho_detalhado → quais termos estão em quais documentos
# Quero processos que mencionem "pagamento" E "autorizado"
com_ambos = sei.verificar_despacho_estrito(
documentos,
termos_busca=["pagamento", "autorizado"]
)
# Quero saber quais termos foram encontrados em cada documento
mapa = sei.verificar_despacho_detalhado(
documentos,
termos_busca=["pagamento", "autorizado", "pendente", "urgente"]
)
# Resultado: {"Memorando 001/2025": ["PAGAMENTO", "AUTORIZADO"], ...}
for doc, termos in mapa.items():
print(f"{doc}: {termos}")
Exemplo: incluir anexo e formatar despacho
sei.pesquisar_processo("0012345-67.2025.8.19.0000")
# Inclui um arquivo externo (PDF, planilha, etc.) como Anexo
sei.incluir_anexo(
nome_arvore="Balancete Julho 2025",
caminho_arquivo="C:/Users/joao/Downloads/balancete_jul25.pdf",
)
# Inclui um despacho de encaminhamento pelo texto padrão cadastrado no SEI
sei.incluir_despacho(texto_padrao="Encaminhamento SUPCONC")
# Formata o despacho (substitui variáveis no editor CKEditor5 do SEI)
numero_gr = sei.copiar_informacoes_documento() # obtém número do último documento
sei.formatar_despacho(
titulo="Senhor Coordenador,",
valor="1.500,00",
valor_por_extenso="um mil e quinhentos reais",
data="01/07/2025",
num_documento=numero_gr,
index_doc=numero_gr,
)
3. apipoint — Integração com SharePoint e Microsoft 365
SharePoint
A classe SharePoint gerencia arquivos e pastas em um site SharePoint corporativo. A autenticação usa cookies do navegador extraídos automaticamente via automaweb.
from jupiter import SharePoint
sp = SharePoint(site_url="https://tenant.sharepoint.com/sites/SetorContabil")
# Download de um arquivo específico
sp.download_arquivo(
caminho_sharepoint="/sites/SetorContabil/Shared Documents/Relatorios/balancete.xlsx",
pasta_local="C:/Users/joao/Downloads",
)
# Upload de um arquivo
sp.upload_arquivo(
caminho_local="C:/Users/joao/Downloads/resultado_julho.xlsx",
pasta_sharepoint="/sites/SetorContabil/Shared Documents/Resultados",
)
# Download recursivo de uma pasta inteira
sp.download_pasta(
pasta_sharepoint="/sites/SetorContabil/Shared Documents/Backup",
pasta_local="C:/Users/joao/Backup_SP",
)
# Verificar existência antes de sobrescrever
caminho = "/sites/SetorContabil/Shared Documents/Resultados/resultado_julho.xlsx"
if not sp.existe_arquivo(caminho):
sp.upload_arquivo("C:/Users/joao/Downloads/resultado_julho.xlsx",
"/sites/SetorContabil/Shared Documents/Resultados")
# Criar estrutura de pastas e limpar arquivos antigos
sp.criar_pasta("/sites/SetorContabil/Shared Documents/2025/Julho")
sp.excluir_arquivo("/sites/SetorContabil/Shared Documents/2025/Junho/temp.xlsx")
GraphAPI (Teams e Outlook)
A classe GraphAPI usa autenticação app-only (client credentials) para integrar com Microsoft Teams e Outlook. Requer autorização prévia da TI.
from jupiter import GraphAPI
graph = GraphAPI(
tenant_id="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
client_id="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
client_secret="seu-segredo-aqui",
conta_coorporativa="automacao@sefaz.rj.gov.br",
)
# Enviar e-mail
graph.enviar_email(
titulo="Rotina de Julho concluída",
mensagem="A contabilização de 47 GRs foi concluída com sucesso.",
destinatarios=["joao.silva@sefaz.rj.gov.br", "chefia@sefaz.rj.gov.br"],
)
# Listar e-mails não lidos
mensagens = graph.listar_emails(pasta="Inbox", top=5)
# Responder a um e-mail
graph.responder_email(
id_mensagem="AAMkAGI...",
texto_resposta="Confirmamos o recebimento. Aguarde processamento.",
)
# Enviar alerta via Teams (webhook)
graph.enviar_mensagem(
webhook_url="https://sefaz.webhook.office.com/webhookb2/...",
mensagem="Contabilizacao de julho finalizada.",
destinatarios=["equipe-contabil"],
)
Arquivos XPath (_xpaths.py)
Os módulos siafelibrary_xpaths.py e seilibrary_xpaths.py centralizam os seletores XPath de cada tela do SIAFE e do SEI. São usados internamente pelas classes Siafe e SEI, mas podem ser acessados diretamente para estender a biblioteca ou inspecionar seletores.
Por que XPaths separados?
Quando a interface do SIAFE ou do SEI muda (atualização de sistema), basta atualizar o arquivo _xpaths.py correspondente — o código de lógica de negócio não precisa ser tocado.
Estrutura dos arquivos XPath
siafelibrary_xpaths.py — organizado por tela do SIAFE:
| Classe | Tela |
|---|---|
siafe_xpaths_login |
Tela de login |
xpaths_menu |
Menu principal de navegação |
xpaths_gr |
Guia de Recolhimento |
xpaths_pde |
PD Extra-orçamentária |
xpaths_pdt |
PD de Transferência |
xpaths_np |
Nota Patrimonial |
xpaths_na |
Nota de Aplicação e Resgate |
xpaths_ev |
Nota de Evento |
xpaths_consulta |
Filtros de consulta de GR |
seilibrary_xpaths.py — organizado por área do SEI:
| Classe | Área |
|---|---|
sei_xpaths_login |
Tela de login |
xpaths_pagina_inicial |
Barra de pesquisa e menu da unidade |
xpaths_processos |
Árvore de documentos e iframes |
xpaths_documento |
Formulário de inclusão de documento |
xpaths_controle_processos |
Tabela do Controle de Processos |
Como acessar
# Importação via pacote jupiter (conforme __init__.py)
from jupiter import xpaths_gr, siafe_xpaths_login, sei_xpaths_login
print(xpaths_gr.btn_inserir_gr) # '//*[@id="pt1:tblGuiaRecolhimento:btnInsert"]'
print(siafe_xpaths_login.usuario) # '//*[@id="loginBox:itxUsuario::content"]'
print(sei_xpaths_login.btn_acessar) # '//*[@id="sbmAcessar"]'
# Importação direta dos módulos (para acesso completo)
from jupiter.siafelibrary_xpaths import xpaths_login # nome original sem alias
from jupiter.seilibrary_xpaths import xpaths_login
Exemplo: estendendo a biblioteca com um novo comportamento
from jupiter import Siafe, xpaths_gr
class SiafeCustom(Siafe):
def verificar_numero_gr(self) -> str | None:
"""Retorna o número da GR exibido na tela atual."""
if self.verifica_visivel(xpaths_gr.numero_documento):
return self.obter_texto(xpaths_gr.numero_documento)
return None
Estruturando o dict_map
O dict_map é o mecanismo central de separação entre regras de negócio e automação. Cada chave corresponde ao valor da coluna tipo_id no seu DataFrame; o valor é um dicionário com os campos que o SIAFE exige para aquele tipo de documento.
Referência completa das chaves
regras = {
# ── GR Orçamentária ────────────────────────────────────────────────────
"GR_ORC": {
"TipoDocumento": "01 - Arrecadação", # texto exato do dropdown
"UG": "123456", # código da UG emitente
"DomicilioBancario": "0001", # código para pesquisa
"DomicilioBancarioCompleto": "0001 - BANCO DO BRASIL", # texto para validação
"ExtraOrcamentario": False,
"IEF": "1",
"Fonte": "100",
"FonteRJ": "100",
"TipoDetalhamentoFonte": "0",
"DetalhamentoFonte": "0000", # opcional
"Convenio": "99999",
"TipoPatrimonial": "Ativo",
"ItemPatrimonial": "Bancos Conta Movimento",
"OperacaoPatrimonial": "Entrada de Recursos",
"NaturezaReceita": "11180111", # exclusivo: GR orçamentária
},
# ── GR Extra-orçamentária ──────────────────────────────────────────────
"GR_EXTRA": {
"TipoDocumento": "02 - Extra-orçamentário",
"UG": "654321",
"DomicilioBancario": "0002",
"DomicilioBancarioCompleto": "0002 - CAIXA ECONÔMICA FEDERAL",
"ExtraOrcamentario": True, # ativa o caminho extra-orçamentário
"IEF": "1", "Fonte": "100", "FonteRJ": "100",
"TipoDetalhamentoFonte": "0", "Convenio": "99999",
"TipoPatrimonial": "Passivo",
"ItemPatrimonial": "Obrigações a Pagar",
"OperacaoPatrimonial": "Saída de Recursos",
"TipoCredor": "PJ", # PJ | PF | CG | UG
"Credor": "12345678000199",
},
# ── PDT (Programação de Desembolso de Transferência) ───────────────────
"PDT_01": {
"UG": "123456",
"UGFavorecida": "654321", # opcional; padrão = UG
"DomicilioBancarioOrigem": "0001",
"DomicilioBancarioOrigemCompleto": "0001 - BANCO DO BRASIL",
"DomicilioBancarioDestino": "0002",
"DomicilioBancarioDestinoCompleto": "0002 - CAIXA",
"IEF": "1", "Fonte": "100", "FonteRJ": "100",
"TipoDetalhamentoFonte": "0", "DetalhamentoFonte": "0000",
"Convenio": "99999",
"TipoPatrimonial": "Ativo",
"ItemPatrimonial": "Transferências",
"OperacaoPatrimonial": "899991",
"SelecaoPorValor": True, # seleciona pelo código, não pelo texto
"Regularizacao": "01 - Tipo A", # opcional: PDT de regularização
"JustificativaRegularizacao": "Regularização do mês anterior", # opcional
},
# ── NP com Inscrição Genérica ──────────────────────────────────────────
"NP_IG": {
"UG": "123456",
"TipoPatrimonial": "Ativo",
"ItemPatrimonial": "Ajustes Patrimoniais",
"OperacaoPatrimonial": "Bloqueio",
"SelecaoPorValor": True,
"IEF": "1", "Fonte": "100", "FonteRJ": "100",
"TipoDetalhamentoFonte": "0", "DetalhamentoFonte": "0000",
"DomicilioBancario": "0001",
"InscricaoGenerica": "12345", # código da IG
"TipoInscricaoGenerica": "01 - Bloqueio", # tipo da IG (opcional)
},
# ── NA com Estorno ─────────────────────────────────────────────────────
"NA_ESTORNO": {
"UG": "123456",
"Estorno": True, # marca a caixa de estorno
"TipoPatrimonial": "Ativo",
"ItemPatrimonial": "Aplicações Financeiras",
"OperacaoPatrimonial": "Resgate",
"IEF": "1", "Fonte": "100", "FonteRJ": "100",
"TipoDetalhamentoFonte": "0", "DetalhamentoFonte": "0000",
"DomicilioBancario": "0001 - BANCO DO BRASIL",
},
}
Dicas importantes
- Os textos dos dropdowns devem ser exatamente iguais aos exibidos no SIAFE (copie direto da tela).
- Use
"SelecaoPorValor": Truequando o dropdown tem muitas opções e é mais confiável selecionar pelo código numérico. - O DataFrame deve ter pelo menos as colunas:
id,data,valor,observacao,tipo_id,num_documento(inicialmenteNone),tempo_contab(inicialmenteNone).
Instalação
O módulo apipoint (SharePoint e Graph API) depende de uma versão específica do office365-rest-python-client que ainda não está publicada no PyPI. Instale-a manualmente antes do jupiter:
pip install git+https://github.com/vgrem/office365-rest-python-client.git@630e4e1f7977e28a8354174cc85896421425e4d7
pip install jupiter-subtes
Se você não usar o apipoint, a instalação simples é suficiente:
pip install jupiter-subtes
Dependências
| Biblioteca | Instalação | Uso |
|---|---|---|
selenium >= 4.0.0 |
automática | Controle do navegador |
automaweb |
automática | Biblioteca base de automação web (interna) |
pandas |
automática | Manipulação de DataFrames |
requests |
automática | Chamadas à API REST do SIAFE |
msal |
automática | Autenticação Microsoft (Graph API) |
office365-rest-python-client |
manual (ver acima) | SharePoint e Graph API |
O Google Chrome deve estar instalado e atualizado. O automaweb gerencia o ChromeDriver automaticamente.
Logging
A biblioteca não configura nenhum handler de log por conta própria. Para capturar os erros em arquivo:
import logging
logger = logging.getLogger("jupiter")
handler = logging.FileHandler("automacao.log", encoding="utf-8")
handler.setFormatter(logging.Formatter("%(asctime)s | %(levelname)s | %(message)s"))
logger.addHandler(handler)
logger.setLevel(logging.ERROR)
Arquitetura e Decisões de Design
- Separação de regras de negócio:
Siafenão contém nenhum código de conta, fonte ou UG. Tudo é injetado viadict_map, permitindo que a mesma biblioteca atenda a diferentes sub-setores sem alterações no código-fonte. - Validação antes de prosseguir: após cada preenchimento crítico, o robô relê o campo do SIAFE para confirmar que o valor foi aceito pelo sistema. Se a validação falhar, ele clica em "Voltar" e tenta novamente (até 3 tentativas por lançamento).
- Resiliência a falhas de DOM: todos os métodos de interação com o navegador têm retry automático para
StaleElementReferenceExceptione aguardam o cursor sair do estadowaitantes de prosseguir. - XPaths centralizados: os seletores ficam nos arquivos
_xpaths.pye não no código de automação, facilitando a manutenção quando o SIAFE ou o SEI atualizam a interface. - Callback de sucesso:
gerar_documentoaceita umcallback_sucessochamado a cada documento gerado, permitindo persistência incremental — se o processo cair na metade, os documentos já contabilizados estão salvos.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file jupiter_subtes-1.0.8.tar.gz.
File metadata
- Download URL: jupiter_subtes-1.0.8.tar.gz
- Upload date:
- Size: 43.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1ffe841de32cd69823e87cfeff36b0b1f6f33e1932c23e653d4b70a6bce68b65
|
|
| MD5 |
7ce3b955166c57269185f560ccc7c654
|
|
| BLAKE2b-256 |
2c50c9b0bcd394a8666c8c1700b3820d8ddf4d8a43328c545896ffc9d0e1e9fa
|
File details
Details for the file jupiter_subtes-1.0.8-py3-none-any.whl.
File metadata
- Download URL: jupiter_subtes-1.0.8-py3-none-any.whl
- Upload date:
- Size: 38.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0d97cc0d02f95079173ecb132492af3f8da70f4f35507c774215dbad8de48760
|
|
| MD5 |
4fd5c8de006b2a899ccff01669b87291
|
|
| BLAKE2b-256 |
e5e74f8e51d6d0f34acfe107177c33a36f4ff34b9001ab7f0d0db7683180c92a
|