sicoob-sdk 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,94 @@
1
+ Metadata-Version: 2.4
2
+ Name: sicoob-sdk
3
+ Version: 0.1.0
4
+ Summary: A Python SDK for Sicoob API
5
+ Author: Fábio Thomaz
6
+ Author-email: fabio@ladder.dev.br
7
+ Requires-Python: >=3.7
8
+ Description-Content-Type: text/markdown
9
+ Requires-Dist: requests>=2.25.1
10
+ Requires-Dist: python-dotenv>=0.15.0
11
+ Requires-Dist: pytest>=7.0.0
12
+ Requires-Dist: pytest-mock>=3.6.1
13
+ Dynamic: author
14
+ Dynamic: author-email
15
+ Dynamic: requires-python
16
+
17
+ # Sicoob SDK Python
18
+
19
+ SDK Python para integração com a API do Banco Sicoob
20
+
21
+ ## Instalação
22
+
23
+ ```bash
24
+ pip install -r requirements.txt
25
+ # ou
26
+ pip install -e .
27
+ ```
28
+
29
+ ## Configuração
30
+
31
+ Crie um arquivo `.env` na raiz do projeto com as seguintes variáveis:
32
+
33
+ ```ini
34
+ SICOOB_CLIENT_ID=seu_client_id
35
+ SICOOB_CLIENT_SECRET=seu_client_secret
36
+ SICOOB_CERTIFICADO=caminho/para/certificado.pem
37
+ SICOOB_CHAVE_PRIVADA=caminho/para/chave_privada.key
38
+ ```
39
+
40
+ ## Uso Básico
41
+
42
+ ```python
43
+ from sicoob import Sicoob
44
+
45
+ # Inicializa o cliente
46
+ cliente = Sicoob(
47
+ client_id="seu_client_id",
48
+ client_secret="seu_client_secret",
49
+ certificado="caminho/para/certificado.pem",
50
+ chave_privada="caminho/para/chave_privada.key"
51
+ )
52
+
53
+ # Exemplo: consulta de extratos
54
+ extrato = cliente.consulta_extrato(conta="12345", data_inicio="2023-01-01", data_fim="2023-01-31")
55
+ ```
56
+
57
+ ## API de Boletos
58
+
59
+ A classe `BoletoAPI` permite emitir e consultar boletos bancários:
60
+
61
+ ```python
62
+ from sicoob.boleto import BoletoAPI
63
+
64
+ # Obtém instância do BoletoAPI
65
+ boleto_api = cliente.boleto()
66
+
67
+ # Emitir boleto
68
+ dados_boleto = {
69
+ "numeroContrato": 123456,
70
+ "modalidade": 1,
71
+ "valor": 100.50,
72
+ "beneficiario": {
73
+ "nome": "Nome Beneficiário",
74
+ "documento": "12345678901"
75
+ }
76
+ }
77
+ boleto = boleto_api.emitir_boleto(dados_boleto)
78
+
79
+ # Consultar boleto
80
+ nosso_numero = boleto["nossoNumero"]
81
+ boleto_consultado = boleto_api.consultar_boleto(nosso_numero)
82
+ ```
83
+
84
+ ### Tratamento de Erros
85
+
86
+ A API trata os seguintes casos de erro:
87
+ - **404 Not Found**: Retorna `None` quando o boleto não existe
88
+ - **Erros HTTP (400, 500, etc)**: Levanta exceção com código e mensagem
89
+ - **Erros de conexão**: Levanta exceção com detalhes do erro
90
+
91
+ ## Links Úteis
92
+
93
+ - [Documentação API Sicoob](https://developers.sicoob.com.br)
94
+ - [Portal de Desenvolvedores](https://developers.sicoob.com.br/portal)
@@ -0,0 +1,78 @@
1
+ # Sicoob SDK Python
2
+
3
+ SDK Python para integração com a API do Banco Sicoob
4
+
5
+ ## Instalação
6
+
7
+ ```bash
8
+ pip install -r requirements.txt
9
+ # ou
10
+ pip install -e .
11
+ ```
12
+
13
+ ## Configuração
14
+
15
+ Crie um arquivo `.env` na raiz do projeto com as seguintes variáveis:
16
+
17
+ ```ini
18
+ SICOOB_CLIENT_ID=seu_client_id
19
+ SICOOB_CLIENT_SECRET=seu_client_secret
20
+ SICOOB_CERTIFICADO=caminho/para/certificado.pem
21
+ SICOOB_CHAVE_PRIVADA=caminho/para/chave_privada.key
22
+ ```
23
+
24
+ ## Uso Básico
25
+
26
+ ```python
27
+ from sicoob import Sicoob
28
+
29
+ # Inicializa o cliente
30
+ cliente = Sicoob(
31
+ client_id="seu_client_id",
32
+ client_secret="seu_client_secret",
33
+ certificado="caminho/para/certificado.pem",
34
+ chave_privada="caminho/para/chave_privada.key"
35
+ )
36
+
37
+ # Exemplo: consulta de extratos
38
+ extrato = cliente.consulta_extrato(conta="12345", data_inicio="2023-01-01", data_fim="2023-01-31")
39
+ ```
40
+
41
+ ## API de Boletos
42
+
43
+ A classe `BoletoAPI` permite emitir e consultar boletos bancários:
44
+
45
+ ```python
46
+ from sicoob.boleto import BoletoAPI
47
+
48
+ # Obtém instância do BoletoAPI
49
+ boleto_api = cliente.boleto()
50
+
51
+ # Emitir boleto
52
+ dados_boleto = {
53
+ "numeroContrato": 123456,
54
+ "modalidade": 1,
55
+ "valor": 100.50,
56
+ "beneficiario": {
57
+ "nome": "Nome Beneficiário",
58
+ "documento": "12345678901"
59
+ }
60
+ }
61
+ boleto = boleto_api.emitir_boleto(dados_boleto)
62
+
63
+ # Consultar boleto
64
+ nosso_numero = boleto["nossoNumero"]
65
+ boleto_consultado = boleto_api.consultar_boleto(nosso_numero)
66
+ ```
67
+
68
+ ### Tratamento de Erros
69
+
70
+ A API trata os seguintes casos de erro:
71
+ - **404 Not Found**: Retorna `None` quando o boleto não existe
72
+ - **Erros HTTP (400, 500, etc)**: Levanta exceção com código e mensagem
73
+ - **Erros de conexão**: Levanta exceção com detalhes do erro
74
+
75
+ ## Links Úteis
76
+
77
+ - [Documentação API Sicoob](https://developers.sicoob.com.br)
78
+ - [Portal de Desenvolvedores](https://developers.sicoob.com.br/portal)
@@ -0,0 +1,19 @@
1
+ [project]
2
+ name = "sicoob-sdk"
3
+ version = "0.1.0"
4
+ description = "A Python SDK for Sicoob API"
5
+ readme = "README.md"
6
+ requires-python = ">=3.10"
7
+ dependencies = [
8
+ "requests>=2.25.1",
9
+ "python-dotenv>=0.15.0",
10
+ # Testes
11
+ "pytest>=7.0.0",
12
+ "pytest-mock>=3.6.1",
13
+ ]
14
+
15
+ [dependency-groups]
16
+ dev = [
17
+ "build>=1.2.2.post1",
18
+ "twine>=6.1.0",
19
+ ]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,23 @@
1
+ from setuptools import setup, find_packages
2
+
3
+ setup(
4
+ name="sicoob-sdk",
5
+ version="0.1.2",
6
+ description="SDK Python para integração com a API do Banco Sicoob",
7
+ long_description=open("README.md", encoding='utf-8').read(),
8
+ long_description_content_type="text/markdown",
9
+ author="Fábio Thomaz",
10
+ author_email="fabio@ladder.dev.br",
11
+ packages=find_packages(),
12
+ install_requires=[
13
+ "requests>=2.25.1",
14
+ "python-dotenv>=0.15.0",
15
+ ],
16
+ python_requires=">=3.7",
17
+ classifiers=[
18
+ "Development Status :: 3 - Alpha",
19
+ "Intended Audience :: Developers",
20
+ "License :: OSI Approved :: MIT License",
21
+ "Programming Language :: Python :: 3",
22
+ ],
23
+ )
@@ -0,0 +1,52 @@
1
+ """Módulo principal do SDK Sicoob"""
2
+
3
+ from .client import Sicoob
4
+ from .conta_corrente import ContaCorrenteAPI
5
+ from .pix import PixAPI
6
+ from .boleto import BoletoAPI
7
+ from .exceptions import (
8
+ SicoobError,
9
+ BoletoError,
10
+ BoletoEmissaoError,
11
+ BoletoConsultaError,
12
+ BoletoNaoEncontradoError,
13
+ ContaCorrenteError,
14
+ PixError,
15
+ AutenticacaoError,
16
+ ExtratoError,
17
+ SaldoError,
18
+ TransferenciaError,
19
+ CobrancaPixError,
20
+ CobrancaPixNaoEncontradaError,
21
+ CobrancaPixVencimentoError,
22
+ WebhookPixError,
23
+ WebhookPixNaoEncontradoError,
24
+ LoteCobrancaPixError,
25
+ QrCodePixError
26
+ )
27
+
28
+ __version__ = "0.1.0"
29
+ __all__ = [
30
+ "Sicoob",
31
+ "ContaCorrenteAPI",
32
+ "PixAPI",
33
+ "BoletoAPI",
34
+ "SicoobError",
35
+ "BoletoError",
36
+ "BoletoEmissaoError",
37
+ "BoletoConsultaError",
38
+ "BoletoNaoEncontradoError",
39
+ "ContaCorrenteError",
40
+ "PixError",
41
+ "AutenticacaoError",
42
+ "ExtratoError",
43
+ "SaldoError",
44
+ "TransferenciaError",
45
+ "CobrancaPixError",
46
+ "CobrancaPixNaoEncontradaError",
47
+ "CobrancaPixVencimentoError",
48
+ "WebhookPixError",
49
+ "WebhookPixNaoEncontradoError",
50
+ "LoteCobrancaPixError",
51
+ "QrCodePixError"
52
+ ]
@@ -0,0 +1,38 @@
1
+ from typing import Dict
2
+ import requests
3
+ from .auth import OAuth2Client
4
+ from .constants import BASE_URL, SANDBOX_URL
5
+
6
+
7
+ class APIClientBase:
8
+ """Classe base para APIs do Sicoob"""
9
+
10
+ def __init__(
11
+ self,
12
+ oauth_client: OAuth2Client,
13
+ session: requests.Session,
14
+ sandbox_mode: bool = False,
15
+ ):
16
+ """Inicializa com cliente OAuth e sessão HTTP existente
17
+
18
+ Args:
19
+ oauth_client: Cliente OAuth2 para autenticação
20
+ session: Sessão HTTP existente
21
+ sandbox_mode: Se True, usa URL de sandbox (default: False)
22
+ """
23
+ self.sandbox_mode = sandbox_mode
24
+ self.oauth_client = oauth_client
25
+ self.session = session
26
+
27
+ def _get_base_url(self) -> str:
28
+ """Retorna a URL base conforme modo de operação"""
29
+ return SANDBOX_URL if self.sandbox_mode else BASE_URL
30
+
31
+ def _get_headers(self, scope) -> Dict[str, str]:
32
+ """Retorna headers padrão com token de acesso"""
33
+ token = self.oauth_client.get_access_token(scope)
34
+ return {
35
+ "Authorization": f"Bearer {token}",
36
+ "Content-Type": "application/json",
37
+ "Accept": "application/json",
38
+ }
@@ -0,0 +1,5 @@
1
+ """Módulo de autenticação do SDK Sicoob"""
2
+
3
+ from .oauth import OAuth2Client
4
+
5
+ __all__ = ["OAuth2Client"]
@@ -0,0 +1,68 @@
1
+ import os
2
+ import time
3
+ from dotenv import load_dotenv
4
+ import requests
5
+
6
+
7
+ class OAuth2Client:
8
+ """Cliente OAuth2 para autenticação com a API Sicoob"""
9
+
10
+ def __init__(
11
+ self, client_id=None, certificado=None, chave_privada=None
12
+ ):
13
+ """Inicializa o cliente OAuth2"""
14
+ load_dotenv()
15
+
16
+ self.client_id = client_id or os.getenv("SICOOB_CLIENT_ID")
17
+ self.certificado = certificado or os.getenv("SICOOB_CERTIFICADO")
18
+ self.chave_privada = chave_privada or os.getenv("SICOOB_CHAVE_PRIVADA")
19
+
20
+ self.token_url = "https://auth.sicoob.com.br/auth/realms/cooperado/protocol/openid-connect/token"
21
+ self.token_cache = {} # Cache de tokens por escopo
22
+ self.session = requests.Session()
23
+ self.session.cert = (self.certificado, self.chave_privada)
24
+
25
+ def get_access_token(self, scope=None):
26
+ """Obtém ou renova o token de acesso para o escopo especificado
27
+
28
+ Args:
29
+ scope: Escopo(s) necessário(s) para a API. Exemplos:
30
+ - Cobrança por Boleto: "boletos_inclusao boletos_consulta boletos_alteracao webhooks_alteracao webhooks_consulta webhooks_inclusao"
31
+ - Conta Corrente: "cco_consulta cco_transferencias openid"
32
+ - Recebimento no PIX: "cob.write cob.read cobv.write cobv.read lotecobv.write lotecobv.read pix.write pix.read webhook.read webhook.write payloadlocation.write payloadlocation.read"
33
+
34
+ Returns:
35
+ str: Token de acesso válido para o escopo solicitado
36
+ """
37
+ # Usa escopo padrão se não especificado (para compatibilidade)
38
+ if scope is None:
39
+ scope = "cco_extrato cco_consulta"
40
+
41
+ # Verifica se já existe token válido para este escopo
42
+ if scope in self.token_cache and not self._is_token_expired(scope):
43
+ return self.token_cache[scope]["access_token"]
44
+
45
+ token_data = {
46
+ "grant_type": "client_credentials",
47
+ "client_id": self.client_id,
48
+ "scope": scope,
49
+ }
50
+
51
+ response = self.session.post(self.token_url, data=token_data)
52
+ response.raise_for_status()
53
+
54
+ token_info = response.json()
55
+ token_info["expires_at"] = time.time() + token_info["expires_in"]
56
+
57
+ # Armazena o token no cache por escopo
58
+ self.token_cache[scope] = token_info
59
+
60
+ return token_info["access_token"]
61
+
62
+ def _is_token_expired(self, scope):
63
+ """Verifica se o token para o escopo especificado expirou"""
64
+ if scope not in self.token_cache or "expires_at" not in self.token_cache[scope]:
65
+ return True
66
+ return (
67
+ time.time() >= self.token_cache[scope]["expires_at"] - 60
68
+ ) # 60s de margem