pypix-api 0.0.3__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.
- pypix_api-0.0.3/LICENSE +21 -0
- pypix_api-0.0.3/PKG-INFO +187 -0
- pypix_api-0.0.3/README.md +138 -0
- pypix_api-0.0.3/pypix_api/__init__.py +0 -0
- pypix_api-0.0.3/pypix_api/auth/mtls.py +34 -0
- pypix_api-0.0.3/pypix_api/auth/oauth2.py +99 -0
- pypix_api-0.0.3/pypix_api/banks/base.py +50 -0
- pypix_api-0.0.3/pypix_api/banks/bb.py +18 -0
- pypix_api-0.0.3/pypix_api/banks/cobv_methods.py +101 -0
- pypix_api-0.0.3/pypix_api/banks/sicoob.py +20 -0
- pypix_api-0.0.3/pypix_api/models/pix.py +9 -0
- pypix_api-0.0.3/pypix_api/utils/http_client.py +5 -0
- pypix_api-0.0.3/pypix_api.egg-info/PKG-INFO +187 -0
- pypix_api-0.0.3/pypix_api.egg-info/SOURCES.txt +21 -0
- pypix_api-0.0.3/pypix_api.egg-info/dependency_links.txt +1 -0
- pypix_api-0.0.3/pypix_api.egg-info/requires.txt +10 -0
- pypix_api-0.0.3/pypix_api.egg-info/top_level.txt +1 -0
- pypix_api-0.0.3/pyproject.toml +77 -0
- pypix_api-0.0.3/setup.cfg +4 -0
- pypix_api-0.0.3/tests/test_auth.py +23 -0
- pypix_api-0.0.3/tests/test_banks.py +47 -0
- pypix_api-0.0.3/tests/test_models.py +8 -0
- pypix_api-0.0.3/tests/test_utils.py +20 -0
pypix_api-0.0.3/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Seu Nome
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
pypix_api-0.0.3/PKG-INFO
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pypix-api
|
|
3
|
+
Version: 0.0.3
|
|
4
|
+
Summary: Biblioteca em Python para comunicação com APIs bancárias focada na integração com o PIX
|
|
5
|
+
Author-email: Fábio Thomaz <fabio@ladder.dev.br>
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2025 Seu Nome
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
|
|
28
|
+
Project-URL: Homepage, https://github.com/laddertech/pypix-api
|
|
29
|
+
Project-URL: Repository, https://github.com/laddertech/pypix-api
|
|
30
|
+
Keywords: pix,api,banco,pagamento,brasil
|
|
31
|
+
Classifier: Programming Language :: Python :: 3
|
|
32
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
33
|
+
Classifier: Operating System :: OS Independent
|
|
34
|
+
Classifier: Intended Audience :: Developers
|
|
35
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
36
|
+
Requires-Python: >=3.10
|
|
37
|
+
Description-Content-Type: text/markdown
|
|
38
|
+
License-File: LICENSE
|
|
39
|
+
Requires-Dist: requests>=2.25.1
|
|
40
|
+
Requires-Dist: python-dotenv>=0.15.0
|
|
41
|
+
Requires-Dist: requests-pkcs12>=1.25
|
|
42
|
+
Provides-Extra: dev
|
|
43
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
44
|
+
Requires-Dist: pytest-mock>=3.6.1; extra == "dev"
|
|
45
|
+
Requires-Dist: build>=1.2.2.post1; extra == "dev"
|
|
46
|
+
Requires-Dist: twine>=6.1.0; extra == "dev"
|
|
47
|
+
Requires-Dist: ruff>=0.4.2; extra == "dev"
|
|
48
|
+
Dynamic: license-file
|
|
49
|
+
|
|
50
|
+
# pypix-api
|
|
51
|
+
|
|
52
|
+
Biblioteca em Python para comunicação com APIs bancárias, focada na integração com o PIX.
|
|
53
|
+
|
|
54
|
+
## Sumário
|
|
55
|
+
|
|
56
|
+
- [pypix-api](#pypix-api)
|
|
57
|
+
- [Sumário](#sumário)
|
|
58
|
+
- [Visão Geral](#visão-geral)
|
|
59
|
+
- [Instalação](#instalação)
|
|
60
|
+
- [Exemplo de Uso](#exemplo-de-uso)
|
|
61
|
+
- [Estrutura do Projeto](#estrutura-do-projeto)
|
|
62
|
+
- [Configuração](#configuração)
|
|
63
|
+
- [Testes](#testes)
|
|
64
|
+
- [Contribuição](#contribuição)
|
|
65
|
+
- [Licença](#licença)
|
|
66
|
+
|
|
67
|
+
## Visão Geral
|
|
68
|
+
|
|
69
|
+
O `pypix-api` facilita a integração de sistemas Python com APIs bancárias brasileiras, com ênfase no ecossistema do PIX. A biblioteca abstrai autenticação, comunicação segura (MTLS/OAuth2), e operações comuns de bancos como Banco do Brasil e Sicoob.
|
|
70
|
+
|
|
71
|
+
## Instalação
|
|
72
|
+
|
|
73
|
+
Recomenda-se o uso de ambiente virtual.
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
pip install .
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Ou, para desenvolvimento:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
git clone https://github.com/seu-usuario/pypix-api.git
|
|
83
|
+
cd pypix-api
|
|
84
|
+
pip install -e .
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Exemplo de Uso
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
from pypix_api.banks.bb import BancoDoBrasil
|
|
91
|
+
|
|
92
|
+
# Instanciação do banco (OAuth2 é inicializado internamente)
|
|
93
|
+
bb = BancoDoBrasil(
|
|
94
|
+
client_id="SEU_CLIENT_ID",
|
|
95
|
+
client_secret="SEU_CLIENT_SECRET",
|
|
96
|
+
cert_path="caminho/do/certificado.pem",
|
|
97
|
+
key_path="caminho/da/chave.key"
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
# Exemplo: Cobrança com Vencimento
|
|
101
|
+
payload = {
|
|
102
|
+
"calendario": {
|
|
103
|
+
"dataDeVencimento": "2025-12-31",
|
|
104
|
+
"validadeAposVencimento": 30
|
|
105
|
+
},
|
|
106
|
+
"loc": {
|
|
107
|
+
"id": 789
|
|
108
|
+
},
|
|
109
|
+
"devedor": {
|
|
110
|
+
"logradouro": "Alameda Souza, Numero 80, Bairro Braz",
|
|
111
|
+
"cidade": "Recife",
|
|
112
|
+
"uf": "PE",
|
|
113
|
+
"cep": "70011750",
|
|
114
|
+
"cpf": "12345678909",
|
|
115
|
+
"nome": "Francisco da Silva"
|
|
116
|
+
},
|
|
117
|
+
"valor": {
|
|
118
|
+
"original": "123.45",
|
|
119
|
+
"multa": {
|
|
120
|
+
"modalidade": "2",
|
|
121
|
+
"valorPerc": "15.00"
|
|
122
|
+
},
|
|
123
|
+
"juros": {
|
|
124
|
+
"modalidade": "2",
|
|
125
|
+
"valorPerc": "2.00"
|
|
126
|
+
},
|
|
127
|
+
"desconto": {
|
|
128
|
+
"modalidade": "1",
|
|
129
|
+
"descontoDataFixa": [
|
|
130
|
+
{
|
|
131
|
+
"data": "2025-11-30",
|
|
132
|
+
"valorPerc": "30.00"
|
|
133
|
+
}
|
|
134
|
+
]
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
"chave": "5f84a4c5-c5cb-4599-9f13-7eb4d419dacc",
|
|
138
|
+
"solicitacaoPagador": "Cobrança dos serviços prestados."
|
|
139
|
+
}
|
|
140
|
+
cobv = bb.criar_cobv(txid="uuid-unico", body=payload)
|
|
141
|
+
print(cobv)
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## Estrutura do Projeto
|
|
145
|
+
|
|
146
|
+
```
|
|
147
|
+
pypix_api/
|
|
148
|
+
├── auth/ # Autenticação (MTLS, OAuth2)
|
|
149
|
+
├── banks/ # Integrações com bancos (BB, Sicoob, métodos PIX)
|
|
150
|
+
├── models/ # Modelos de dados do PIX
|
|
151
|
+
├── utils/ # Utilitários (HTTP client, helpers)
|
|
152
|
+
tests/ # Testes automatizados
|
|
153
|
+
openapi.yaml # Especificação OpenAPI (se aplicável)
|
|
154
|
+
pyproject.toml # Configuração do projeto Python
|
|
155
|
+
Makefile # Comandos úteis para desenvolvimento
|
|
156
|
+
.env.exemplo # Exemplo de variáveis de ambiente
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Configuração
|
|
160
|
+
|
|
161
|
+
Crie um arquivo `.env` baseado em `.env.exemplo` com as credenciais e configurações necessárias para autenticação e acesso às APIs bancárias.
|
|
162
|
+
|
|
163
|
+
## Testes
|
|
164
|
+
|
|
165
|
+
Para rodar os testes automatizados:
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
make test
|
|
169
|
+
```
|
|
170
|
+
ou diretamente com pytest:
|
|
171
|
+
```bash
|
|
172
|
+
pytest
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## Contribuição
|
|
176
|
+
|
|
177
|
+
Contribuições são bem-vindas! Siga os passos:
|
|
178
|
+
|
|
179
|
+
1. Fork este repositório
|
|
180
|
+
2. Crie uma branch (`git checkout -b feature/nova-funcionalidade`)
|
|
181
|
+
3. Commit suas alterações (`git commit -am 'Adiciona nova funcionalidade'`)
|
|
182
|
+
4. Push para a branch (`git push origin feature/nova-funcionalidade`)
|
|
183
|
+
5. Abra um Pull Request
|
|
184
|
+
|
|
185
|
+
## Licença
|
|
186
|
+
|
|
187
|
+
Este projeto está licenciado sob os termos da licença MIT.
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# pypix-api
|
|
2
|
+
|
|
3
|
+
Biblioteca em Python para comunicação com APIs bancárias, focada na integração com o PIX.
|
|
4
|
+
|
|
5
|
+
## Sumário
|
|
6
|
+
|
|
7
|
+
- [pypix-api](#pypix-api)
|
|
8
|
+
- [Sumário](#sumário)
|
|
9
|
+
- [Visão Geral](#visão-geral)
|
|
10
|
+
- [Instalação](#instalação)
|
|
11
|
+
- [Exemplo de Uso](#exemplo-de-uso)
|
|
12
|
+
- [Estrutura do Projeto](#estrutura-do-projeto)
|
|
13
|
+
- [Configuração](#configuração)
|
|
14
|
+
- [Testes](#testes)
|
|
15
|
+
- [Contribuição](#contribuição)
|
|
16
|
+
- [Licença](#licença)
|
|
17
|
+
|
|
18
|
+
## Visão Geral
|
|
19
|
+
|
|
20
|
+
O `pypix-api` facilita a integração de sistemas Python com APIs bancárias brasileiras, com ênfase no ecossistema do PIX. A biblioteca abstrai autenticação, comunicação segura (MTLS/OAuth2), e operações comuns de bancos como Banco do Brasil e Sicoob.
|
|
21
|
+
|
|
22
|
+
## Instalação
|
|
23
|
+
|
|
24
|
+
Recomenda-se o uso de ambiente virtual.
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pip install .
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Ou, para desenvolvimento:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
git clone https://github.com/seu-usuario/pypix-api.git
|
|
34
|
+
cd pypix-api
|
|
35
|
+
pip install -e .
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Exemplo de Uso
|
|
39
|
+
|
|
40
|
+
```python
|
|
41
|
+
from pypix_api.banks.bb import BancoDoBrasil
|
|
42
|
+
|
|
43
|
+
# Instanciação do banco (OAuth2 é inicializado internamente)
|
|
44
|
+
bb = BancoDoBrasil(
|
|
45
|
+
client_id="SEU_CLIENT_ID",
|
|
46
|
+
client_secret="SEU_CLIENT_SECRET",
|
|
47
|
+
cert_path="caminho/do/certificado.pem",
|
|
48
|
+
key_path="caminho/da/chave.key"
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
# Exemplo: Cobrança com Vencimento
|
|
52
|
+
payload = {
|
|
53
|
+
"calendario": {
|
|
54
|
+
"dataDeVencimento": "2025-12-31",
|
|
55
|
+
"validadeAposVencimento": 30
|
|
56
|
+
},
|
|
57
|
+
"loc": {
|
|
58
|
+
"id": 789
|
|
59
|
+
},
|
|
60
|
+
"devedor": {
|
|
61
|
+
"logradouro": "Alameda Souza, Numero 80, Bairro Braz",
|
|
62
|
+
"cidade": "Recife",
|
|
63
|
+
"uf": "PE",
|
|
64
|
+
"cep": "70011750",
|
|
65
|
+
"cpf": "12345678909",
|
|
66
|
+
"nome": "Francisco da Silva"
|
|
67
|
+
},
|
|
68
|
+
"valor": {
|
|
69
|
+
"original": "123.45",
|
|
70
|
+
"multa": {
|
|
71
|
+
"modalidade": "2",
|
|
72
|
+
"valorPerc": "15.00"
|
|
73
|
+
},
|
|
74
|
+
"juros": {
|
|
75
|
+
"modalidade": "2",
|
|
76
|
+
"valorPerc": "2.00"
|
|
77
|
+
},
|
|
78
|
+
"desconto": {
|
|
79
|
+
"modalidade": "1",
|
|
80
|
+
"descontoDataFixa": [
|
|
81
|
+
{
|
|
82
|
+
"data": "2025-11-30",
|
|
83
|
+
"valorPerc": "30.00"
|
|
84
|
+
}
|
|
85
|
+
]
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
"chave": "5f84a4c5-c5cb-4599-9f13-7eb4d419dacc",
|
|
89
|
+
"solicitacaoPagador": "Cobrança dos serviços prestados."
|
|
90
|
+
}
|
|
91
|
+
cobv = bb.criar_cobv(txid="uuid-unico", body=payload)
|
|
92
|
+
print(cobv)
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Estrutura do Projeto
|
|
96
|
+
|
|
97
|
+
```
|
|
98
|
+
pypix_api/
|
|
99
|
+
├── auth/ # Autenticação (MTLS, OAuth2)
|
|
100
|
+
├── banks/ # Integrações com bancos (BB, Sicoob, métodos PIX)
|
|
101
|
+
├── models/ # Modelos de dados do PIX
|
|
102
|
+
├── utils/ # Utilitários (HTTP client, helpers)
|
|
103
|
+
tests/ # Testes automatizados
|
|
104
|
+
openapi.yaml # Especificação OpenAPI (se aplicável)
|
|
105
|
+
pyproject.toml # Configuração do projeto Python
|
|
106
|
+
Makefile # Comandos úteis para desenvolvimento
|
|
107
|
+
.env.exemplo # Exemplo de variáveis de ambiente
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Configuração
|
|
111
|
+
|
|
112
|
+
Crie um arquivo `.env` baseado em `.env.exemplo` com as credenciais e configurações necessárias para autenticação e acesso às APIs bancárias.
|
|
113
|
+
|
|
114
|
+
## Testes
|
|
115
|
+
|
|
116
|
+
Para rodar os testes automatizados:
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
make test
|
|
120
|
+
```
|
|
121
|
+
ou diretamente com pytest:
|
|
122
|
+
```bash
|
|
123
|
+
pytest
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Contribuição
|
|
127
|
+
|
|
128
|
+
Contribuições são bem-vindas! Siga os passos:
|
|
129
|
+
|
|
130
|
+
1. Fork este repositório
|
|
131
|
+
2. Crie uma branch (`git checkout -b feature/nova-funcionalidade`)
|
|
132
|
+
3. Commit suas alterações (`git commit -am 'Adiciona nova funcionalidade'`)
|
|
133
|
+
4. Push para a branch (`git push origin feature/nova-funcionalidade`)
|
|
134
|
+
5. Abra um Pull Request
|
|
135
|
+
|
|
136
|
+
## Licença
|
|
137
|
+
|
|
138
|
+
Este projeto está licenciado sob os termos da licença MIT.
|
|
File without changes
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
from typing import BinaryIO
|
|
2
|
+
|
|
3
|
+
import requests
|
|
4
|
+
import requests_pkcs12
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def get_session_with_mtls(
|
|
8
|
+
cert: str | None = None,
|
|
9
|
+
pvk: str | None = None,
|
|
10
|
+
cert_pfx: str | bytes | BinaryIO | None = None,
|
|
11
|
+
pwd_pfx: str | None = None,
|
|
12
|
+
sandbox_mode: bool = False,
|
|
13
|
+
) -> requests.Session:
|
|
14
|
+
session = requests.Session()
|
|
15
|
+
|
|
16
|
+
if not sandbox_mode:
|
|
17
|
+
if cert_pfx and pwd_pfx:
|
|
18
|
+
# Configura autenticação com PFX
|
|
19
|
+
pkcs12_adapter = requests_pkcs12.Pkcs12Adapter(
|
|
20
|
+
pkcs12_data=cert_pfx if isinstance(cert_pfx, bytes) else None,
|
|
21
|
+
pkcs12_filename=cert_pfx if isinstance(cert_pfx, str) else None,
|
|
22
|
+
pkcs12_password=pwd_pfx,
|
|
23
|
+
)
|
|
24
|
+
session.mount('https://', pkcs12_adapter)
|
|
25
|
+
elif cert and pvk:
|
|
26
|
+
# Configura autenticação com PEM (manter compatibilidade)
|
|
27
|
+
session.cert = (cert, pvk)
|
|
28
|
+
else:
|
|
29
|
+
raise ValueError(
|
|
30
|
+
'É necessário fornecer certificado e chave privada (PEM) '
|
|
31
|
+
'ou certificado PFX e senha'
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
return session
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import time
|
|
3
|
+
import requests
|
|
4
|
+
from typing import BinaryIO
|
|
5
|
+
from dotenv import load_dotenv
|
|
6
|
+
|
|
7
|
+
from pypix_api.auth.mtls import get_session_with_mtls
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class OAuth2Client:
|
|
11
|
+
"""Cliente OAuth2 para autenticação com a API"""
|
|
12
|
+
|
|
13
|
+
def __init__(
|
|
14
|
+
self,
|
|
15
|
+
token_url: str,
|
|
16
|
+
client_id: str | None = None,
|
|
17
|
+
cert: str | None = None,
|
|
18
|
+
pvk: str | None = None,
|
|
19
|
+
cert_pfx: str | bytes | BinaryIO | None = None,
|
|
20
|
+
pwd_pfx: str | None = None,
|
|
21
|
+
sandbox_mode: bool = False,
|
|
22
|
+
) -> None:
|
|
23
|
+
"""Inicializa o cliente OAuth2
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
client_id: Client ID para autenticação OAuth2
|
|
27
|
+
cert: Path para o certificado PEM (opcional)
|
|
28
|
+
pvk: Path para a chave privada PEM (opcional)
|
|
29
|
+
cert_pfx: Path ou dados do certificado PFX (opcional)
|
|
30
|
+
pwd_pfx: Senha do certificado PFX (opcional)
|
|
31
|
+
sandbox_mode: Se True, não requer certificado (default: False)
|
|
32
|
+
"""
|
|
33
|
+
load_dotenv()
|
|
34
|
+
|
|
35
|
+
self.client_id = client_id or os.getenv('CLIENT_ID')
|
|
36
|
+
self.cert = cert or os.getenv('CERT')
|
|
37
|
+
self.pvk = pvk or os.getenv('PVK')
|
|
38
|
+
self.cert_pfx = cert_pfx or os.getenv('CERT_PFX')
|
|
39
|
+
self.pwd_pfx = pwd_pfx or os.getenv('PWD_PFX')
|
|
40
|
+
|
|
41
|
+
self.token_url = token_url # URL de autenticação OAuth2
|
|
42
|
+
self.token_cache = {} # Cache de tokens por escopo
|
|
43
|
+
self.session = requests.Session()
|
|
44
|
+
|
|
45
|
+
self.sandbox_mode = sandbox_mode
|
|
46
|
+
|
|
47
|
+
if not self.sandbox_mode:
|
|
48
|
+
self.session = get_session_with_mtls(
|
|
49
|
+
cert=self.cert,
|
|
50
|
+
pvk=self.pvk,
|
|
51
|
+
cert_pfx=self.cert_pfx,
|
|
52
|
+
pwd_pfx=self.pwd_pfx,
|
|
53
|
+
sandbox_mode=self.sandbox_mode,
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
def get_token(self, scope: str | None = None) -> str:
|
|
57
|
+
"""Obtém ou renova o token de acesso para o escopo especificado
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
scope: Escopo(s) necessário(s) para a API. Exemplos:
|
|
61
|
+
- Cobrança por Boleto: "boletos_inclusao boletos_consulta boletos_alteracao webhooks_alteracao webhooks_consulta webhooks_inclusao"
|
|
62
|
+
- Conta Corrente: "cco_consulta cco_transferencias openid"
|
|
63
|
+
- 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"
|
|
64
|
+
|
|
65
|
+
Returns:
|
|
66
|
+
str: Token de acesso válido para o escopo solicitado
|
|
67
|
+
"""
|
|
68
|
+
# Usa escopo padrão se não especificado (para compatibilidade)
|
|
69
|
+
if scope is None:
|
|
70
|
+
scope = 'cco_extrato cco_consulta'
|
|
71
|
+
|
|
72
|
+
# Verifica se já existe token válido para este escopo
|
|
73
|
+
if scope in self.token_cache and not self._is_token_expired(scope):
|
|
74
|
+
return self.token_cache[scope]['access_token']
|
|
75
|
+
|
|
76
|
+
token_data = {
|
|
77
|
+
'grant_type': 'client_credentials',
|
|
78
|
+
'client_id': self.client_id,
|
|
79
|
+
'scope': scope,
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
response = self.session.post(self.token_url, data=token_data)
|
|
83
|
+
response.raise_for_status()
|
|
84
|
+
|
|
85
|
+
token_info = response.json()
|
|
86
|
+
token_info['expires_at'] = time.time() + token_info['expires_in']
|
|
87
|
+
|
|
88
|
+
# Armazena o token no cache por escopo
|
|
89
|
+
self.token_cache[scope] = token_info
|
|
90
|
+
|
|
91
|
+
return token_info['access_token']
|
|
92
|
+
|
|
93
|
+
def _is_token_expired(self, scope: str) -> bool:
|
|
94
|
+
"""Verifica se o token para o escopo especificado expirou"""
|
|
95
|
+
if scope not in self.token_cache or 'expires_at' not in self.token_cache[scope]:
|
|
96
|
+
return True
|
|
97
|
+
return (
|
|
98
|
+
time.time() >= self.token_cache[scope]['expires_at'] - 60
|
|
99
|
+
) # 60s de margem
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
from abc import ABC
|
|
2
|
+
from typing import BinaryIO
|
|
3
|
+
from pypix_api.auth.oauth2 import OAuth2Client
|
|
4
|
+
from pypix_api.banks.cobv_methods import CobVMethods
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class BankPixAPIBase(CobVMethods, ABC):
|
|
8
|
+
"""Classe base abstrata para clientes Pix de bancos."""
|
|
9
|
+
|
|
10
|
+
BASE_URL = None
|
|
11
|
+
TOKEN_URL = None
|
|
12
|
+
SCOPES = None
|
|
13
|
+
|
|
14
|
+
def __init__(
|
|
15
|
+
self,
|
|
16
|
+
client_id: str | None = None,
|
|
17
|
+
cert: str | None = None,
|
|
18
|
+
pvk: str | None = None,
|
|
19
|
+
cert_pfx: str | bytes | BinaryIO | None = None,
|
|
20
|
+
pwd_pfx: str | None = None,
|
|
21
|
+
sandbox_mode: bool = False,
|
|
22
|
+
) -> None:
|
|
23
|
+
if not self.BASE_URL or not self.TOKEN_URL or not self.SCOPES:
|
|
24
|
+
raise ValueError(
|
|
25
|
+
'BASE_URL, TOKEN_URL e SCOPES devem ser definidos na subclasse.'
|
|
26
|
+
)
|
|
27
|
+
self.sandbox_mode = sandbox_mode
|
|
28
|
+
self.client_id = client_id
|
|
29
|
+
|
|
30
|
+
self.oauth = OAuth2Client(
|
|
31
|
+
token_url=self.TOKEN_URL,
|
|
32
|
+
client_id=client_id,
|
|
33
|
+
cert=cert,
|
|
34
|
+
pvk=pvk,
|
|
35
|
+
cert_pfx=cert_pfx,
|
|
36
|
+
pwd_pfx=pwd_pfx,
|
|
37
|
+
sandbox_mode=sandbox_mode,
|
|
38
|
+
)
|
|
39
|
+
self.session = self.oauth.session
|
|
40
|
+
|
|
41
|
+
def _create_headers(self) -> dict[str, str]:
|
|
42
|
+
"""
|
|
43
|
+
Cria os headers necessários para as requisições.
|
|
44
|
+
"""
|
|
45
|
+
token = self.oauth.get_token()
|
|
46
|
+
return {
|
|
47
|
+
'Authorization': f'Bearer {token}',
|
|
48
|
+
'Content-Type': 'application/json',
|
|
49
|
+
'client_id': self.client_id or '',
|
|
50
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from pypix_api.banks.base import BankPixAPIBase
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class BBPixAPI(BankPixAPIBase):
|
|
5
|
+
"""Banco do Brasil API client for Pix operations."""
|
|
6
|
+
|
|
7
|
+
BASE_URL = "https://api.bb.com.br/pix/v1"
|
|
8
|
+
SANDBOX_BASE_URL = "https://api.sandbox.bb.com.br/pix/v1"
|
|
9
|
+
TOKEN_URL = "https://oauth.bb.com.br/oauth/token"
|
|
10
|
+
SCOPES = "pix.read pix.write"
|
|
11
|
+
|
|
12
|
+
def get_base_url(self) -> str:
|
|
13
|
+
"""
|
|
14
|
+
Retorna a URL base da API, diferenciando entre produção e sandbox.
|
|
15
|
+
"""
|
|
16
|
+
if self.sandbox_mode:
|
|
17
|
+
return self.SANDBOX_BASE_URL
|
|
18
|
+
return self.BASE_URL
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Módulo cobv_methods.py
|
|
3
|
+
|
|
4
|
+
Este módulo define a classe CobVMethods, que implementa métodos para
|
|
5
|
+
integração com cobranças Pix com vencimento (CobV) via API bancária.
|
|
6
|
+
Inclui operações para criar, revisar, consultar e listar cobranças com vencimento,
|
|
7
|
+
utilizando autenticação OAuth2 e requisições HTTP.
|
|
8
|
+
|
|
9
|
+
Principais funcionalidades:
|
|
10
|
+
- Criação de cobrança com vencimento (CobV)
|
|
11
|
+
- Revisão de cobrança com vencimento
|
|
12
|
+
- Consulta de cobrança por txid
|
|
13
|
+
- Listagem de cobranças por período e filtros
|
|
14
|
+
|
|
15
|
+
Dependências:
|
|
16
|
+
- OAuth2 para autenticação (self.oauth)
|
|
17
|
+
- Cliente HTTP de sessão (self.session)
|
|
18
|
+
- Python 3.10+ (tipos nativos)
|
|
19
|
+
|
|
20
|
+
Autor: [Fabio Thomaz(fabio@ladder.dev.br)]
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
from typing import Any
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class CobVMethods: # pylint: disable=E1101
|
|
27
|
+
"""
|
|
28
|
+
Métodos para lidar com cobrança Pix com vencimento (CobV).
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
def criar_cobv(self, txid: str, body: dict[str, Any]) -> dict[str, Any]:
|
|
32
|
+
"""
|
|
33
|
+
Cria uma cobrança com vencimento (CobV).
|
|
34
|
+
"""
|
|
35
|
+
headers = self._create_headers()
|
|
36
|
+
url = f'{self.get_base_url()}/cobv/{txid}'
|
|
37
|
+
resp = self.session.put(url, headers=headers, json=body)
|
|
38
|
+
resp.raise_for_status()
|
|
39
|
+
return resp.json()
|
|
40
|
+
|
|
41
|
+
def revisar_cobv(self, txid: str, body: dict[str, Any]) -> dict[str, Any]:
|
|
42
|
+
"""
|
|
43
|
+
Revisa uma cobrança com vencimento (CobV).
|
|
44
|
+
"""
|
|
45
|
+
headers = self._create_headers()
|
|
46
|
+
url = f'{self.get_base_url()}/cobv/{txid}'
|
|
47
|
+
resp = self.session.patch(url, headers=headers, json=body)
|
|
48
|
+
resp.raise_for_status()
|
|
49
|
+
return resp.json()
|
|
50
|
+
|
|
51
|
+
def consultar_cobv(
|
|
52
|
+
self, txid: str, revisao: int | None
|
|
53
|
+
) -> dict[str, Any]:
|
|
54
|
+
"""
|
|
55
|
+
Consulta uma cobrança com vencimento (CobV) por txid.
|
|
56
|
+
"""
|
|
57
|
+
headers = self._create_headers()
|
|
58
|
+
params = {}
|
|
59
|
+
if revisao is not None:
|
|
60
|
+
params['revisao'] = revisao
|
|
61
|
+
url = f'{self.get_base_url()}/cobv/{txid}'
|
|
62
|
+
resp = self.session.get(url, headers=headers, params=params)
|
|
63
|
+
resp.raise_for_status()
|
|
64
|
+
return resp.json()
|
|
65
|
+
|
|
66
|
+
def listar_cobv(
|
|
67
|
+
self,
|
|
68
|
+
inicio: str,
|
|
69
|
+
fim: str,
|
|
70
|
+
cpf: str | None = None,
|
|
71
|
+
cnpj: str | None = None,
|
|
72
|
+
location_presente: bool | None = None,
|
|
73
|
+
status: str | None = None,
|
|
74
|
+
lote_cob_v_id: int | None = None,
|
|
75
|
+
pagina_atual: int | None = None,
|
|
76
|
+
itens_por_pagina: int | None = None,
|
|
77
|
+
) -> dict[str, Any]:
|
|
78
|
+
"""
|
|
79
|
+
Consulta lista de cobranças com vencimento (CobV).
|
|
80
|
+
"""
|
|
81
|
+
headers = self._create_headers()
|
|
82
|
+
params = {'inicio': inicio, 'fim': fim}
|
|
83
|
+
if cpf:
|
|
84
|
+
params['cpf'] = cpf
|
|
85
|
+
if cnpj:
|
|
86
|
+
params['cnpj'] = cnpj
|
|
87
|
+
if location_presente is not None:
|
|
88
|
+
params['locationPresente'] = str(location_presente).lower()
|
|
89
|
+
if status:
|
|
90
|
+
params['status'] = status
|
|
91
|
+
if lote_cob_v_id is not None:
|
|
92
|
+
params['loteCobVId'] = lote_cob_v_id
|
|
93
|
+
if pagina_atual is not None:
|
|
94
|
+
params['paginaAtual'] = pagina_atual
|
|
95
|
+
if itens_por_pagina is not None:
|
|
96
|
+
params['itensPorPagina'] = itens_por_pagina
|
|
97
|
+
|
|
98
|
+
url = f'{self.get_base_url()}/cobv'
|
|
99
|
+
resp = self.session.get(url, headers=headers, params=params)
|
|
100
|
+
resp.raise_for_status()
|
|
101
|
+
return resp.json()
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from pypix_api.banks.base import BankPixAPIBase
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class SicoobPixAPI(BankPixAPIBase):
|
|
5
|
+
"""Sicoob API client for Pix operations."""
|
|
6
|
+
|
|
7
|
+
BASE_URL = "https://api.sicoob.com.br/pix/api/v2"
|
|
8
|
+
SANDBOX_BASE_URL = "https://sandbox.sicoob.com.br/sicoob/sandbox/pix/api/v2"
|
|
9
|
+
TOKEN_URL = (
|
|
10
|
+
"https://auth.sicoob.com.br/auth/realms/sicoob/protocol/openid-connect/token"
|
|
11
|
+
)
|
|
12
|
+
SCOPES = "cob.read cob.write pix.read pix.write"
|
|
13
|
+
|
|
14
|
+
def get_base_url(self) -> str:
|
|
15
|
+
"""
|
|
16
|
+
Retorna a URL base da API, diferenciando entre produção e sandbox.
|
|
17
|
+
"""
|
|
18
|
+
if self.sandbox_mode:
|
|
19
|
+
return self.SANDBOX_BASE_URL
|
|
20
|
+
return self.BASE_URL
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pypix-api
|
|
3
|
+
Version: 0.0.3
|
|
4
|
+
Summary: Biblioteca em Python para comunicação com APIs bancárias focada na integração com o PIX
|
|
5
|
+
Author-email: Fábio Thomaz <fabio@ladder.dev.br>
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2025 Seu Nome
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
|
|
28
|
+
Project-URL: Homepage, https://github.com/laddertech/pypix-api
|
|
29
|
+
Project-URL: Repository, https://github.com/laddertech/pypix-api
|
|
30
|
+
Keywords: pix,api,banco,pagamento,brasil
|
|
31
|
+
Classifier: Programming Language :: Python :: 3
|
|
32
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
33
|
+
Classifier: Operating System :: OS Independent
|
|
34
|
+
Classifier: Intended Audience :: Developers
|
|
35
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
36
|
+
Requires-Python: >=3.10
|
|
37
|
+
Description-Content-Type: text/markdown
|
|
38
|
+
License-File: LICENSE
|
|
39
|
+
Requires-Dist: requests>=2.25.1
|
|
40
|
+
Requires-Dist: python-dotenv>=0.15.0
|
|
41
|
+
Requires-Dist: requests-pkcs12>=1.25
|
|
42
|
+
Provides-Extra: dev
|
|
43
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
44
|
+
Requires-Dist: pytest-mock>=3.6.1; extra == "dev"
|
|
45
|
+
Requires-Dist: build>=1.2.2.post1; extra == "dev"
|
|
46
|
+
Requires-Dist: twine>=6.1.0; extra == "dev"
|
|
47
|
+
Requires-Dist: ruff>=0.4.2; extra == "dev"
|
|
48
|
+
Dynamic: license-file
|
|
49
|
+
|
|
50
|
+
# pypix-api
|
|
51
|
+
|
|
52
|
+
Biblioteca em Python para comunicação com APIs bancárias, focada na integração com o PIX.
|
|
53
|
+
|
|
54
|
+
## Sumário
|
|
55
|
+
|
|
56
|
+
- [pypix-api](#pypix-api)
|
|
57
|
+
- [Sumário](#sumário)
|
|
58
|
+
- [Visão Geral](#visão-geral)
|
|
59
|
+
- [Instalação](#instalação)
|
|
60
|
+
- [Exemplo de Uso](#exemplo-de-uso)
|
|
61
|
+
- [Estrutura do Projeto](#estrutura-do-projeto)
|
|
62
|
+
- [Configuração](#configuração)
|
|
63
|
+
- [Testes](#testes)
|
|
64
|
+
- [Contribuição](#contribuição)
|
|
65
|
+
- [Licença](#licença)
|
|
66
|
+
|
|
67
|
+
## Visão Geral
|
|
68
|
+
|
|
69
|
+
O `pypix-api` facilita a integração de sistemas Python com APIs bancárias brasileiras, com ênfase no ecossistema do PIX. A biblioteca abstrai autenticação, comunicação segura (MTLS/OAuth2), e operações comuns de bancos como Banco do Brasil e Sicoob.
|
|
70
|
+
|
|
71
|
+
## Instalação
|
|
72
|
+
|
|
73
|
+
Recomenda-se o uso de ambiente virtual.
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
pip install .
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Ou, para desenvolvimento:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
git clone https://github.com/seu-usuario/pypix-api.git
|
|
83
|
+
cd pypix-api
|
|
84
|
+
pip install -e .
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Exemplo de Uso
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
from pypix_api.banks.bb import BancoDoBrasil
|
|
91
|
+
|
|
92
|
+
# Instanciação do banco (OAuth2 é inicializado internamente)
|
|
93
|
+
bb = BancoDoBrasil(
|
|
94
|
+
client_id="SEU_CLIENT_ID",
|
|
95
|
+
client_secret="SEU_CLIENT_SECRET",
|
|
96
|
+
cert_path="caminho/do/certificado.pem",
|
|
97
|
+
key_path="caminho/da/chave.key"
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
# Exemplo: Cobrança com Vencimento
|
|
101
|
+
payload = {
|
|
102
|
+
"calendario": {
|
|
103
|
+
"dataDeVencimento": "2025-12-31",
|
|
104
|
+
"validadeAposVencimento": 30
|
|
105
|
+
},
|
|
106
|
+
"loc": {
|
|
107
|
+
"id": 789
|
|
108
|
+
},
|
|
109
|
+
"devedor": {
|
|
110
|
+
"logradouro": "Alameda Souza, Numero 80, Bairro Braz",
|
|
111
|
+
"cidade": "Recife",
|
|
112
|
+
"uf": "PE",
|
|
113
|
+
"cep": "70011750",
|
|
114
|
+
"cpf": "12345678909",
|
|
115
|
+
"nome": "Francisco da Silva"
|
|
116
|
+
},
|
|
117
|
+
"valor": {
|
|
118
|
+
"original": "123.45",
|
|
119
|
+
"multa": {
|
|
120
|
+
"modalidade": "2",
|
|
121
|
+
"valorPerc": "15.00"
|
|
122
|
+
},
|
|
123
|
+
"juros": {
|
|
124
|
+
"modalidade": "2",
|
|
125
|
+
"valorPerc": "2.00"
|
|
126
|
+
},
|
|
127
|
+
"desconto": {
|
|
128
|
+
"modalidade": "1",
|
|
129
|
+
"descontoDataFixa": [
|
|
130
|
+
{
|
|
131
|
+
"data": "2025-11-30",
|
|
132
|
+
"valorPerc": "30.00"
|
|
133
|
+
}
|
|
134
|
+
]
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
"chave": "5f84a4c5-c5cb-4599-9f13-7eb4d419dacc",
|
|
138
|
+
"solicitacaoPagador": "Cobrança dos serviços prestados."
|
|
139
|
+
}
|
|
140
|
+
cobv = bb.criar_cobv(txid="uuid-unico", body=payload)
|
|
141
|
+
print(cobv)
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## Estrutura do Projeto
|
|
145
|
+
|
|
146
|
+
```
|
|
147
|
+
pypix_api/
|
|
148
|
+
├── auth/ # Autenticação (MTLS, OAuth2)
|
|
149
|
+
├── banks/ # Integrações com bancos (BB, Sicoob, métodos PIX)
|
|
150
|
+
├── models/ # Modelos de dados do PIX
|
|
151
|
+
├── utils/ # Utilitários (HTTP client, helpers)
|
|
152
|
+
tests/ # Testes automatizados
|
|
153
|
+
openapi.yaml # Especificação OpenAPI (se aplicável)
|
|
154
|
+
pyproject.toml # Configuração do projeto Python
|
|
155
|
+
Makefile # Comandos úteis para desenvolvimento
|
|
156
|
+
.env.exemplo # Exemplo de variáveis de ambiente
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Configuração
|
|
160
|
+
|
|
161
|
+
Crie um arquivo `.env` baseado em `.env.exemplo` com as credenciais e configurações necessárias para autenticação e acesso às APIs bancárias.
|
|
162
|
+
|
|
163
|
+
## Testes
|
|
164
|
+
|
|
165
|
+
Para rodar os testes automatizados:
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
make test
|
|
169
|
+
```
|
|
170
|
+
ou diretamente com pytest:
|
|
171
|
+
```bash
|
|
172
|
+
pytest
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## Contribuição
|
|
176
|
+
|
|
177
|
+
Contribuições são bem-vindas! Siga os passos:
|
|
178
|
+
|
|
179
|
+
1. Fork este repositório
|
|
180
|
+
2. Crie uma branch (`git checkout -b feature/nova-funcionalidade`)
|
|
181
|
+
3. Commit suas alterações (`git commit -am 'Adiciona nova funcionalidade'`)
|
|
182
|
+
4. Push para a branch (`git push origin feature/nova-funcionalidade`)
|
|
183
|
+
5. Abra um Pull Request
|
|
184
|
+
|
|
185
|
+
## Licença
|
|
186
|
+
|
|
187
|
+
Este projeto está licenciado sob os termos da licença MIT.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
pypix_api/__init__.py
|
|
5
|
+
pypix_api.egg-info/PKG-INFO
|
|
6
|
+
pypix_api.egg-info/SOURCES.txt
|
|
7
|
+
pypix_api.egg-info/dependency_links.txt
|
|
8
|
+
pypix_api.egg-info/requires.txt
|
|
9
|
+
pypix_api.egg-info/top_level.txt
|
|
10
|
+
pypix_api/auth/mtls.py
|
|
11
|
+
pypix_api/auth/oauth2.py
|
|
12
|
+
pypix_api/banks/base.py
|
|
13
|
+
pypix_api/banks/bb.py
|
|
14
|
+
pypix_api/banks/cobv_methods.py
|
|
15
|
+
pypix_api/banks/sicoob.py
|
|
16
|
+
pypix_api/models/pix.py
|
|
17
|
+
pypix_api/utils/http_client.py
|
|
18
|
+
tests/test_auth.py
|
|
19
|
+
tests/test_banks.py
|
|
20
|
+
tests/test_models.py
|
|
21
|
+
tests/test_utils.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
pypix_api
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "pypix-api"
|
|
3
|
+
version = "0.0.3"
|
|
4
|
+
description = "Biblioteca em Python para comunicação com APIs bancárias focada na integração com o PIX"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.10"
|
|
7
|
+
authors = [
|
|
8
|
+
{ name = "Fábio Thomaz", email = "fabio@ladder.dev.br" }
|
|
9
|
+
]
|
|
10
|
+
license.file = "LICENSE"
|
|
11
|
+
keywords = ["pix", "api", "banco", "pagamento", "brasil"]
|
|
12
|
+
classifiers = [
|
|
13
|
+
"Programming Language :: Python :: 3",
|
|
14
|
+
"License :: OSI Approved :: MIT License",
|
|
15
|
+
"Operating System :: OS Independent",
|
|
16
|
+
"Intended Audience :: Developers",
|
|
17
|
+
"Topic :: Software Development :: Libraries :: Python Modules"
|
|
18
|
+
]
|
|
19
|
+
dependencies = [
|
|
20
|
+
"requests>=2.25.1",
|
|
21
|
+
"python-dotenv>=0.15.0",
|
|
22
|
+
"requests-pkcs12>=1.25"
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
[project.urls]
|
|
26
|
+
Homepage = "https://github.com/laddertech/pypix-api"
|
|
27
|
+
Repository = "https://github.com/laddertech/pypix-api"
|
|
28
|
+
[project.optional-dependencies]
|
|
29
|
+
dev = [
|
|
30
|
+
"pytest>=7.0.0",
|
|
31
|
+
"pytest-mock>=3.6.1",
|
|
32
|
+
"build>=1.2.2.post1",
|
|
33
|
+
"twine>=6.1.0",
|
|
34
|
+
"ruff>=0.4.2"
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
[build-system]
|
|
38
|
+
requires = ["setuptools>=61.0", "wheel"]
|
|
39
|
+
build-backend = "setuptools.build_meta"
|
|
40
|
+
|
|
41
|
+
[tool.ruff]
|
|
42
|
+
# Configurações base do Ruff
|
|
43
|
+
line-length = 88
|
|
44
|
+
exclude = [
|
|
45
|
+
".venv",
|
|
46
|
+
"build",
|
|
47
|
+
"dist",
|
|
48
|
+
"__pycache__",
|
|
49
|
+
".pytest_cache",
|
|
50
|
+
".ruff_cache",
|
|
51
|
+
]
|
|
52
|
+
|
|
53
|
+
[tool.ruff.lint]
|
|
54
|
+
select = [
|
|
55
|
+
"E", # pycodestyle errors
|
|
56
|
+
"W", # pycodestyle warnings
|
|
57
|
+
"F", # pyflakes
|
|
58
|
+
"I", # isort
|
|
59
|
+
"B", # flake8-bugbear
|
|
60
|
+
"C", # flake8-comprehensions
|
|
61
|
+
"UP", # pyupgrade
|
|
62
|
+
"YTT", # flake8-2020
|
|
63
|
+
"ANN", # flake8-annotations
|
|
64
|
+
"S", # flake8-bandit
|
|
65
|
+
"RUF", # Ruff-specific rules
|
|
66
|
+
]
|
|
67
|
+
ignore = [
|
|
68
|
+
"E501", # Line too long (handled by black)
|
|
69
|
+
"S101", # Use of print (handled by black)
|
|
70
|
+
]
|
|
71
|
+
|
|
72
|
+
# Configurações específicas
|
|
73
|
+
[tool.ruff.lint.isort]
|
|
74
|
+
known-first-party = ["pypix_api"]
|
|
75
|
+
|
|
76
|
+
[tool.ruff.format]
|
|
77
|
+
quote-style = "single"
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from pypix_api.auth.oauth2 import OAuth2Client
|
|
2
|
+
|
|
3
|
+
def test_oauth2client_init(monkeypatch):
|
|
4
|
+
class DummySession:
|
|
5
|
+
pass
|
|
6
|
+
monkeypatch.setattr("pypix_api.auth.oauth2.get_session_with_mtls", lambda *a, **kw: DummySession())
|
|
7
|
+
client = OAuth2Client(
|
|
8
|
+
token_url="token_url",
|
|
9
|
+
client_id="client_id",
|
|
10
|
+
cert="cert_path",
|
|
11
|
+
pvk="key_path",
|
|
12
|
+
cert_pfx="cert.pfx",
|
|
13
|
+
pwd_pfx="senha",
|
|
14
|
+
sandbox_mode=False,
|
|
15
|
+
)
|
|
16
|
+
assert client.client_id == "client_id"
|
|
17
|
+
assert client.cert == "cert_path"
|
|
18
|
+
assert client.pvk == "key_path"
|
|
19
|
+
assert client.cert_pfx == "cert.pfx"
|
|
20
|
+
assert client.pwd_pfx == "senha"
|
|
21
|
+
assert client.token_url == "token_url"
|
|
22
|
+
assert client.sandbox_mode is False
|
|
23
|
+
assert isinstance(client.session, DummySession)
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
from unittest.mock import patch, MagicMock
|
|
3
|
+
from pypix_api.banks.base import BankPixAPIBase
|
|
4
|
+
from pypix_api.banks.bb import BBPixAPI
|
|
5
|
+
from pypix_api.banks.sicoob import SicoobPixAPI
|
|
6
|
+
from pypix_api.banks.cobv_methods import CobVMethods
|
|
7
|
+
|
|
8
|
+
class DummyCobVMethods(CobVMethods):
|
|
9
|
+
def criar_cobv(self, txid, body):
|
|
10
|
+
return {"txid": txid, "body": body}
|
|
11
|
+
def revisar_cobv(self, txid, body):
|
|
12
|
+
return {"txid": txid, "body": body}
|
|
13
|
+
def consultar_cobv(self, txid):
|
|
14
|
+
return {"txid": txid}
|
|
15
|
+
def listar_cobv(self):
|
|
16
|
+
return []
|
|
17
|
+
|
|
18
|
+
def test_bankpixapibase_init():
|
|
19
|
+
class DummyBank(BankPixAPIBase, DummyCobVMethods):
|
|
20
|
+
BASE_URL = "https://dummy"
|
|
21
|
+
TOKEN_URL = "https://dummy/token"
|
|
22
|
+
SCOPES = ["dummy.scope"]
|
|
23
|
+
|
|
24
|
+
import sys
|
|
25
|
+
with patch("pypix_api.banks.base.OAuth2Client", MagicMock()), \
|
|
26
|
+
patch("pypix_api.auth.mtls.get_session_with_mtls", MagicMock(return_value=object())):
|
|
27
|
+
bank = DummyBank("id", "secret", "cert", "key")
|
|
28
|
+
assert hasattr(bank, "session")
|
|
29
|
+
assert hasattr(bank, "oauth")
|
|
30
|
+
|
|
31
|
+
def test_bb_pix_api_inheritance():
|
|
32
|
+
with patch("pypix_api.banks.base.OAuth2Client", MagicMock()), \
|
|
33
|
+
patch("pypix_api.auth.mtls.get_session_with_mtls", MagicMock(return_value=object())):
|
|
34
|
+
api = BBPixAPI("id", "secret", "cert", "key")
|
|
35
|
+
assert isinstance(api, BankPixAPIBase)
|
|
36
|
+
|
|
37
|
+
def test_sicoob_pix_api_inheritance():
|
|
38
|
+
with patch("pypix_api.banks.base.OAuth2Client", MagicMock()), \
|
|
39
|
+
patch("pypix_api.auth.mtls.get_session_with_mtls", MagicMock(return_value=object())):
|
|
40
|
+
api = SicoobPixAPI("id", "secret", "cert", "key")
|
|
41
|
+
assert isinstance(api, BankPixAPIBase)
|
|
42
|
+
|
|
43
|
+
def test_cobv_methods_criar():
|
|
44
|
+
cobv = DummyCobVMethods()
|
|
45
|
+
result = cobv.criar_cobv("123", {"valor": 10})
|
|
46
|
+
assert result["txid"] == "123"
|
|
47
|
+
assert result["body"]["valor"] == 10
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
from pypix_api.models.pix import PixCobranca
|
|
3
|
+
|
|
4
|
+
def test_pix_cobranca_init():
|
|
5
|
+
cobranca = PixCobranca(txid="abc123", valor=100.0, status="ATIVA", chave="minha-chave")
|
|
6
|
+
assert cobranca.txid == "abc123"
|
|
7
|
+
assert cobranca.valor == 100.0
|
|
8
|
+
assert cobranca.status == "ATIVA"
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
from pypix_api.utils.http_client import get
|
|
3
|
+
|
|
4
|
+
def test_get(monkeypatch):
|
|
5
|
+
class DummyResponse:
|
|
6
|
+
def __init__(self):
|
|
7
|
+
self.status_code = 200
|
|
8
|
+
self.text = "ok"
|
|
9
|
+
def json(self):
|
|
10
|
+
return {"result": "ok"}
|
|
11
|
+
def dummy_requests_get(url, headers=None, cert=None):
|
|
12
|
+
assert url == "http://test"
|
|
13
|
+
assert headers == {"Authorization": "Bearer token"}
|
|
14
|
+
assert cert == "cert.pem"
|
|
15
|
+
return DummyResponse()
|
|
16
|
+
monkeypatch.setattr("requests.get", dummy_requests_get)
|
|
17
|
+
response = get("http://test", headers={"Authorization": "Bearer token"}, cert="cert.pem")
|
|
18
|
+
assert response.status_code == 200
|
|
19
|
+
assert response.text == "ok"
|
|
20
|
+
assert response.json() == {"result": "ok"}
|