brbank 0.0.1__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.
Files changed (53) hide show
  1. brbank-0.0.1/.github/workflows/ci.yml +18 -0
  2. brbank-0.0.1/.github/workflows/publish.yml +16 -0
  3. brbank-0.0.1/.gitignore +11 -0
  4. brbank-0.0.1/CLAUDE.md +28 -0
  5. brbank-0.0.1/LICENSE +21 -0
  6. brbank-0.0.1/PKG-INFO +150 -0
  7. brbank-0.0.1/README.md +126 -0
  8. brbank-0.0.1/docs/bb-duvidas.md +83 -0
  9. brbank-0.0.1/docs/pinbank-duvidas.md +40 -0
  10. brbank-0.0.1/docs/pix-duvidas.md +82 -0
  11. brbank-0.0.1/docs/sicoob-duvidas.md +76 -0
  12. brbank-0.0.1/docs/sicredi-duvidas.md +68 -0
  13. brbank-0.0.1/pyproject.toml +63 -0
  14. brbank-0.0.1/src/brbank/__init__.py +51 -0
  15. brbank-0.0.1/src/brbank/adapter.py +53 -0
  16. brbank-0.0.1/src/brbank/adapters/__init__.py +0 -0
  17. brbank-0.0.1/src/brbank/adapters/bb.py +487 -0
  18. brbank-0.0.1/src/brbank/adapters/inter.py +350 -0
  19. brbank-0.0.1/src/brbank/adapters/pinbank.py +309 -0
  20. brbank-0.0.1/src/brbank/adapters/pix_bacen.py +721 -0
  21. brbank-0.0.1/src/brbank/adapters/sicoob.py +423 -0
  22. brbank-0.0.1/src/brbank/adapters/sicredi.py +425 -0
  23. brbank-0.0.1/src/brbank/auth.py +223 -0
  24. brbank-0.0.1/src/brbank/capacidades.py +18 -0
  25. brbank-0.0.1/src/brbank/documento.py +66 -0
  26. brbank-0.0.1/src/brbank/envelope.py +87 -0
  27. brbank-0.0.1/src/brbank/erros.py +55 -0
  28. brbank-0.0.1/src/brbank/mascara.py +106 -0
  29. brbank-0.0.1/src/brbank/modelos.py +158 -0
  30. brbank-0.0.1/src/brbank/orquestrador.py +111 -0
  31. brbank-0.0.1/src/brbank/registro.py +35 -0
  32. brbank-0.0.1/src/brbank/status.py +40 -0
  33. brbank-0.0.1/src/brbank/transporte.py +230 -0
  34. brbank-0.0.1/tests/__init__.py +0 -0
  35. brbank-0.0.1/tests/bb_falso.py +92 -0
  36. brbank-0.0.1/tests/conftest.py +59 -0
  37. brbank-0.0.1/tests/inter_falso.py +72 -0
  38. brbank-0.0.1/tests/pinbank_falso.py +86 -0
  39. brbank-0.0.1/tests/pix_falso.py +137 -0
  40. brbank-0.0.1/tests/sicoob_falso.py +91 -0
  41. brbank-0.0.1/tests/sicredi_falso.py +98 -0
  42. brbank-0.0.1/tests/test_auth.py +58 -0
  43. brbank-0.0.1/tests/test_bb.py +355 -0
  44. brbank-0.0.1/tests/test_contrato.py +247 -0
  45. brbank-0.0.1/tests/test_inter.py +168 -0
  46. brbank-0.0.1/tests/test_modelos.py +94 -0
  47. brbank-0.0.1/tests/test_orquestrador.py +120 -0
  48. brbank-0.0.1/tests/test_pinbank.py +388 -0
  49. brbank-0.0.1/tests/test_pix_bacen.py +392 -0
  50. brbank-0.0.1/tests/test_sicoob.py +232 -0
  51. brbank-0.0.1/tests/test_sicredi.py +371 -0
  52. brbank-0.0.1/tests/test_transporte.py +147 -0
  53. brbank-0.0.1/uv.lock +798 -0
@@ -0,0 +1,18 @@
1
+ name: ci
2
+ on:
3
+ push:
4
+ branches: [main]
5
+ pull_request:
6
+ jobs:
7
+ test:
8
+ runs-on: ubuntu-latest
9
+ strategy:
10
+ matrix:
11
+ python: ["3.11", "3.12"]
12
+ steps:
13
+ - uses: actions/checkout@v4
14
+ - uses: astral-sh/setup-uv@v5
15
+ - run: uv sync --python ${{ matrix.python }}
16
+ - run: uv run ruff check .
17
+ - run: uv run ruff format --check .
18
+ - run: uv run pytest --cov=brbank
@@ -0,0 +1,16 @@
1
+ name: publish
2
+ on:
3
+ release:
4
+ types: [published]
5
+ jobs:
6
+ pypi:
7
+ runs-on: ubuntu-latest
8
+ environment: pypi
9
+ permissions:
10
+ id-token: write
11
+ contents: read
12
+ steps:
13
+ - uses: actions/checkout@v4
14
+ - uses: astral-sh/setup-uv@v5
15
+ - run: uv build
16
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,11 @@
1
+ .venv/
2
+ __pycache__/
3
+ *.pyc
4
+ .pytest_cache/
5
+ .ruff_cache/
6
+ .coverage
7
+ dist/
8
+ *.pem
9
+ *.pfx
10
+ *.crt
11
+ *.key
brbank-0.0.1/CLAUDE.md ADDED
@@ -0,0 +1,28 @@
1
+ # CLAUDE.md
2
+
3
+ Biblioteca `brbank` (cobranca bancaria unificada). Nao importar nada do Odoo.
4
+
5
+ ```bash
6
+ uv sync # instala (inclui o entry point brbank.adapters)
7
+ uv run pytest # testes (sem rede: httpx.MockTransport)
8
+ uv run pytest --cov=brbank # cobertura (meta 80% no core)
9
+ uv run ruff check . # lint
10
+ ```
11
+
12
+ ## Layout
13
+
14
+ - `src/brbank/`: `modelos` (B1), `adapter` (B2), `capacidades` (B3), `registro` (B4),
15
+ `transporte` (B5), `auth` (B6), `envelope` (B7), `erros` (B8), `status` (B9),
16
+ `orquestrador` (B10), `mascara` (LGPD), `documento` (CPF/CNPJ).
17
+ - `src/brbank/adapters/<banco>.py`: um adapter por banco, registrado em
18
+ `[project.entry-points."brbank.adapters"]`.
19
+ - `tests/test_contrato.py`: suite comum registrar -> consultar -> baixar; adapter
20
+ novo entra em `FABRICAS` com um servidor falso.
21
+
22
+ ## Regras
23
+
24
+ - Dinheiro sempre `Decimal`. Nunca logar nem guardar PII/segredo em claro: usar `mascarar`.
25
+ - CNPJ alfanumerico: A-Z sem letras vedadas, DV por ASCII-48.
26
+ - Adapter portado de modulo Odoo: citar a origem no docstring e listar divergencias.
27
+ - Texto sem travessao nem caractere tipografico (so teclado QWERTY). Commits:
28
+ `[ADD]`/`[FIX]` em portugues, sem Co-Authored-By, trailer `Assisted-by: Claude`.
brbank-0.0.1/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 KMEE
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.
brbank-0.0.1/PKG-INFO ADDED
@@ -0,0 +1,150 @@
1
+ Metadata-Version: 2.5
2
+ Name: brbank
3
+ Version: 0.0.1
4
+ Summary: Cobranca bancaria unificada (boleto e Pix) para bancos brasileiros, independente do Odoo
5
+ Project-URL: Homepage, https://github.com/kmee/brbank
6
+ Project-URL: Issues, https://github.com/kmee/brbank/issues
7
+ Author-email: KMEE <info@kmee.com.br>
8
+ License: MIT
9
+ License-File: LICENSE
10
+ Keywords: asyncio,banco,boleto,brasil,cobranca,pix
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Framework :: AsyncIO
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3 :: Only
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Topic :: Office/Business :: Financial
19
+ Requires-Python: >=3.11
20
+ Requires-Dist: cryptography>=50.0.2
21
+ Requires-Dist: httpx[http2]>=0.27
22
+ Requires-Dist: pydantic>=2.6
23
+ Description-Content-Type: text/markdown
24
+
25
+ # brbank
26
+
27
+ Biblioteca Python assincrona para emitir e acompanhar boletos e cobrancas Pix em
28
+ bancos brasileiros por uma interface unica. Nao importa nada do Odoo: o modulo
29
+ `l10n_br_payment_boleto` e uma das faces possiveis.
30
+
31
+ Licenca MIT. Python 3.11+. **Alfa:** nenhum adapter foi validado em sandbox de
32
+ banco (`validado_sandbox = False`); o contrato de cada banco vem da documentacao
33
+ publica e de fontes de terceiros, com as duvidas em `docs/<banco>-duvidas.md`.
34
+ Estado: primeira fatia (modelo canonico, contrato
35
+ de adapter, transporte, autenticacao, orquestrador e os adapters da tabela abaixo).
36
+
37
+ ## Bancos suportados
38
+
39
+ Todos os adapters passam pela mesma suite de contrato (registrar, consultar, baixar) contra um
40
+ servidor falso. "Origem" diz de onde veio o contrato: **Odoo** = portado de um modulo que ja roda
41
+ em producao (o adapter da biblioteca ainda nao rodou contra o banco), **ACBr** = levantado por leitura
42
+ do ACBr, usado so como documentacao, e de fontes de terceiros.
43
+
44
+ | Banco | Adapter (entry point) | Produto | Capacidades declaradas | Origem |
45
+ | --- | --- | --- | --- | --- |
46
+ | Inter (077) | `inter` | Cobranca v3, boleto hibrido | hibrido, so hibrido, baixa, PDF, webhook | Odoo |
47
+ | PinBank | `pinbank` | Boleto, envelope AES-CBC | baixa | Odoo |
48
+ | Sicoob (756) | `sicoob` | Cobranca v3, boleto hibrido | hibrido, alteracao, baixa | ACBr |
49
+ | Sicredi (748) | `sicredi` | Cobranca v2 | hibrido, alteracao, baixa, webhook | ACBr |
50
+ | Banco do Brasil (001) | `bb` | Cobranca v2 | alteracao, baixa | ACBr |
51
+
52
+ Pix (BACEN `/cob`, `/cobv`, `/webhook`) por um adapter generico, `pix_bacen`, com um perfil por PSP
53
+ (host, escopos, headers e quirks): Inter, Banco do Brasil, Sicoob, Sicredi, Itau, Bradesco,
54
+ Santander e Efi. Capacidades: Pix cob e cobv, webhook, baixa.
55
+
56
+ Fora desta lista por enquanto: BNB (sem referencia de Pix confiavel), Caixa, Safra, Banrisul,
57
+ Unicred, BTG e C6 (planejados), gateways como Mercado Pago, PagBank e Stone (sob demanda) e a
58
+ variante ECOMM do Sicredi. Banco novo = um adapter com `BankAdapter` e um entry point em
59
+ `brbank.adapters`; veja `docs/` para o que cada banco ainda deixa em aberto.
60
+
61
+ **Nenhum adapter da biblioteca foi validado em sandbox.** Sicoob, Sicredi, Banco do Brasil e os
62
+ perfis Pix trazem `validado_sandbox = False` no codigo e so passam a `True` depois de rodar contra o
63
+ ambiente real do banco. Inter e PinBank herdam a logica de modulos Odoo em producao, mas o adapter
64
+ da biblioteca tambem ainda nao rodou contra o banco.
65
+
66
+ ## Uso
67
+
68
+ ```python
69
+ from brbank import Orquestrador
70
+ from brbank.adapters.inter import InterAdapter, InterConfig
71
+
72
+ config = InterConfig(
73
+ conta="matriz",
74
+ client_id="...",
75
+ client_secret="...",
76
+ conta_corrente="123456",
77
+ ambiente="sandbox",
78
+ certificado_pem=cert_bytes,
79
+ chave_pem=chave_bytes, # vindos do cofre
80
+ )
81
+ adapter = InterAdapter(config)
82
+ orquestrador = Orquestrador(adapter, concorrencia=10)
83
+
84
+ registrado = await orquestrador.emitir(titulo) # idempotente por chave
85
+ resultados = await orquestrador.emitir_em_varios(lote) # falha isolada por titulo
86
+ ```
87
+
88
+ Um banco novo e um pacote que registra o adapter no entry point `brbank.adapters`:
89
+
90
+ ```toml
91
+ [project.entry-points."brbank.adapters"]
92
+ inter = "brbank.adapters.inter:InterAdapter"
93
+ pinbank = "brbank.adapters.pinbank:PinbankAdapter"
94
+ sicoob = "brbank.adapters.sicoob:SicoobAdapter"
95
+
96
+ sicredi = "brbank.adapters.sicredi:SicrediAdapter"
97
+
98
+ pix_bacen = "brbank.adapters.pix_bacen:PixBacenAdapter"
99
+ ```
100
+
101
+ O `PinbankAdapter` usa OAuth2 `password` e payload cifrado AES-CBC (`EnvelopeAesCbc`),
102
+ registra, consulta e baixa por `NossoNumero`, e nao tem webhook nem PDF. Contrato em
103
+ aberto: `docs/pinbank-duvidas.md`.
104
+
105
+ O `SicoobAdapter` (Cobranca Bancaria v3, boleto hibrido) usa OAuth2 `client_credentials`
106
+ sem `client_secret` (a identidade e o mTLS), header `client_id`, id do titulo = nosso
107
+ numero, registra, consulta, baixa e envia instrucao (prorrogacao, abatimento, protesto).
108
+ Sem PDF e sem webhook declarados. **`validado_sandbox = False`**: contrato montado de
109
+ documentacao de terceiros, nunca executado contra o Sicoob. Duvidas: `docs/sicoob-duvidas.md`.
110
+
111
+ O `BancoDoBrasilAdapter` (`bb`, API Cobranca v2, convenio de 6 ou 7 digitos) usa OAuth2
112
+ `client_credentials` e a chave `gw-dev-app-key` em query param; registra, consulta, baixa,
113
+ prorroga e abate, sem webhook nem PDF. Nasce com `validado_sandbox = False`: ver
114
+ `docs/bb-duvidas.md`.
115
+
116
+ O `SicrediAdapter` (API de Cobranca v2, OAuth2 `password`) registra, consulta, baixa e
117
+ altera (prorrogacao e abatimento); webhook sem assinatura exige reconsulta. Nasce com
118
+ `validado_sandbox = False`; contrato em aberto: `docs/sicredi-duvidas.md`.
119
+
120
+ O `PixBacenAdapter` fala a API Pix do BACEN (`/cob`, `/cobv`, `/webhook`, devolucao) e
121
+ muda de banco por `PerfilPsp`: `inter`, `bb`, `sicoob`, `sicredi`, `itau`, `bradesco`,
122
+ `santander` e `efi` (BNB sem perfil). Todos com `validado_sandbox = False` ate rodar no
123
+ sandbox. O `txid` vem da chave de idempotencia, o copia-e-cola e o `txid` chegam em
124
+ `TituloRegistrado`, e `CONCLUIDA` sem Pix na consulta nao liquida. Duvidas e quirks:
125
+ `docs/pix-duvidas.md`.
126
+
127
+ ```python
128
+ config = PixBacenConfig(
129
+ perfil="sicoob",
130
+ conta="matriz",
131
+ chave_pix="...",
132
+ client_id="...",
133
+ ambiente="producao",
134
+ certificado_pem=cert,
135
+ chave_pem=chave,
136
+ )
137
+ adapter = PixBacenAdapter(config)
138
+ ```
139
+
140
+ `brbank.criar_adapter("inter", config)` resolve pelo nome e
141
+ `adapter.suporta(Capacidade.PDF)` consulta as capacidades em runtime.
142
+
143
+ ## Regras
144
+
145
+ - Valores em `Decimal` (float e recusado). Percentuais em unidade de percentual.
146
+ - Nome, documento e endereco ficam fora do `repr`; log, erro e resposta bruta
147
+ passam por `brbank.mascara.mascarar`.
148
+ - Retry so para 429, 5xx e erro de transporte. Status desconhecido no banco
149
+ levanta erro, nunca vira "pago".
150
+ - Webhook gera `EventoCanonico` e nao confirma nada: reconsulte antes de liquidar.
brbank-0.0.1/README.md ADDED
@@ -0,0 +1,126 @@
1
+ # brbank
2
+
3
+ Biblioteca Python assincrona para emitir e acompanhar boletos e cobrancas Pix em
4
+ bancos brasileiros por uma interface unica. Nao importa nada do Odoo: o modulo
5
+ `l10n_br_payment_boleto` e uma das faces possiveis.
6
+
7
+ Licenca MIT. Python 3.11+. **Alfa:** nenhum adapter foi validado em sandbox de
8
+ banco (`validado_sandbox = False`); o contrato de cada banco vem da documentacao
9
+ publica e de fontes de terceiros, com as duvidas em `docs/<banco>-duvidas.md`.
10
+ Estado: primeira fatia (modelo canonico, contrato
11
+ de adapter, transporte, autenticacao, orquestrador e os adapters da tabela abaixo).
12
+
13
+ ## Bancos suportados
14
+
15
+ Todos os adapters passam pela mesma suite de contrato (registrar, consultar, baixar) contra um
16
+ servidor falso. "Origem" diz de onde veio o contrato: **Odoo** = portado de um modulo que ja roda
17
+ em producao (o adapter da biblioteca ainda nao rodou contra o banco), **ACBr** = levantado por leitura
18
+ do ACBr, usado so como documentacao, e de fontes de terceiros.
19
+
20
+ | Banco | Adapter (entry point) | Produto | Capacidades declaradas | Origem |
21
+ | --- | --- | --- | --- | --- |
22
+ | Inter (077) | `inter` | Cobranca v3, boleto hibrido | hibrido, so hibrido, baixa, PDF, webhook | Odoo |
23
+ | PinBank | `pinbank` | Boleto, envelope AES-CBC | baixa | Odoo |
24
+ | Sicoob (756) | `sicoob` | Cobranca v3, boleto hibrido | hibrido, alteracao, baixa | ACBr |
25
+ | Sicredi (748) | `sicredi` | Cobranca v2 | hibrido, alteracao, baixa, webhook | ACBr |
26
+ | Banco do Brasil (001) | `bb` | Cobranca v2 | alteracao, baixa | ACBr |
27
+
28
+ Pix (BACEN `/cob`, `/cobv`, `/webhook`) por um adapter generico, `pix_bacen`, com um perfil por PSP
29
+ (host, escopos, headers e quirks): Inter, Banco do Brasil, Sicoob, Sicredi, Itau, Bradesco,
30
+ Santander e Efi. Capacidades: Pix cob e cobv, webhook, baixa.
31
+
32
+ Fora desta lista por enquanto: BNB (sem referencia de Pix confiavel), Caixa, Safra, Banrisul,
33
+ Unicred, BTG e C6 (planejados), gateways como Mercado Pago, PagBank e Stone (sob demanda) e a
34
+ variante ECOMM do Sicredi. Banco novo = um adapter com `BankAdapter` e um entry point em
35
+ `brbank.adapters`; veja `docs/` para o que cada banco ainda deixa em aberto.
36
+
37
+ **Nenhum adapter da biblioteca foi validado em sandbox.** Sicoob, Sicredi, Banco do Brasil e os
38
+ perfis Pix trazem `validado_sandbox = False` no codigo e so passam a `True` depois de rodar contra o
39
+ ambiente real do banco. Inter e PinBank herdam a logica de modulos Odoo em producao, mas o adapter
40
+ da biblioteca tambem ainda nao rodou contra o banco.
41
+
42
+ ## Uso
43
+
44
+ ```python
45
+ from brbank import Orquestrador
46
+ from brbank.adapters.inter import InterAdapter, InterConfig
47
+
48
+ config = InterConfig(
49
+ conta="matriz",
50
+ client_id="...",
51
+ client_secret="...",
52
+ conta_corrente="123456",
53
+ ambiente="sandbox",
54
+ certificado_pem=cert_bytes,
55
+ chave_pem=chave_bytes, # vindos do cofre
56
+ )
57
+ adapter = InterAdapter(config)
58
+ orquestrador = Orquestrador(adapter, concorrencia=10)
59
+
60
+ registrado = await orquestrador.emitir(titulo) # idempotente por chave
61
+ resultados = await orquestrador.emitir_em_varios(lote) # falha isolada por titulo
62
+ ```
63
+
64
+ Um banco novo e um pacote que registra o adapter no entry point `brbank.adapters`:
65
+
66
+ ```toml
67
+ [project.entry-points."brbank.adapters"]
68
+ inter = "brbank.adapters.inter:InterAdapter"
69
+ pinbank = "brbank.adapters.pinbank:PinbankAdapter"
70
+ sicoob = "brbank.adapters.sicoob:SicoobAdapter"
71
+
72
+ sicredi = "brbank.adapters.sicredi:SicrediAdapter"
73
+
74
+ pix_bacen = "brbank.adapters.pix_bacen:PixBacenAdapter"
75
+ ```
76
+
77
+ O `PinbankAdapter` usa OAuth2 `password` e payload cifrado AES-CBC (`EnvelopeAesCbc`),
78
+ registra, consulta e baixa por `NossoNumero`, e nao tem webhook nem PDF. Contrato em
79
+ aberto: `docs/pinbank-duvidas.md`.
80
+
81
+ O `SicoobAdapter` (Cobranca Bancaria v3, boleto hibrido) usa OAuth2 `client_credentials`
82
+ sem `client_secret` (a identidade e o mTLS), header `client_id`, id do titulo = nosso
83
+ numero, registra, consulta, baixa e envia instrucao (prorrogacao, abatimento, protesto).
84
+ Sem PDF e sem webhook declarados. **`validado_sandbox = False`**: contrato montado de
85
+ documentacao de terceiros, nunca executado contra o Sicoob. Duvidas: `docs/sicoob-duvidas.md`.
86
+
87
+ O `BancoDoBrasilAdapter` (`bb`, API Cobranca v2, convenio de 6 ou 7 digitos) usa OAuth2
88
+ `client_credentials` e a chave `gw-dev-app-key` em query param; registra, consulta, baixa,
89
+ prorroga e abate, sem webhook nem PDF. Nasce com `validado_sandbox = False`: ver
90
+ `docs/bb-duvidas.md`.
91
+
92
+ O `SicrediAdapter` (API de Cobranca v2, OAuth2 `password`) registra, consulta, baixa e
93
+ altera (prorrogacao e abatimento); webhook sem assinatura exige reconsulta. Nasce com
94
+ `validado_sandbox = False`; contrato em aberto: `docs/sicredi-duvidas.md`.
95
+
96
+ O `PixBacenAdapter` fala a API Pix do BACEN (`/cob`, `/cobv`, `/webhook`, devolucao) e
97
+ muda de banco por `PerfilPsp`: `inter`, `bb`, `sicoob`, `sicredi`, `itau`, `bradesco`,
98
+ `santander` e `efi` (BNB sem perfil). Todos com `validado_sandbox = False` ate rodar no
99
+ sandbox. O `txid` vem da chave de idempotencia, o copia-e-cola e o `txid` chegam em
100
+ `TituloRegistrado`, e `CONCLUIDA` sem Pix na consulta nao liquida. Duvidas e quirks:
101
+ `docs/pix-duvidas.md`.
102
+
103
+ ```python
104
+ config = PixBacenConfig(
105
+ perfil="sicoob",
106
+ conta="matriz",
107
+ chave_pix="...",
108
+ client_id="...",
109
+ ambiente="producao",
110
+ certificado_pem=cert,
111
+ chave_pem=chave,
112
+ )
113
+ adapter = PixBacenAdapter(config)
114
+ ```
115
+
116
+ `brbank.criar_adapter("inter", config)` resolve pelo nome e
117
+ `adapter.suporta(Capacidade.PDF)` consulta as capacidades em runtime.
118
+
119
+ ## Regras
120
+
121
+ - Valores em `Decimal` (float e recusado). Percentuais em unidade de percentual.
122
+ - Nome, documento e endereco ficam fora do `repr`; log, erro e resposta bruta
123
+ passam por `brbank.mascara.mascarar`.
124
+ - Retry so para 429, 5xx e erro de transporte. Status desconhecido no banco
125
+ levanta erro, nunca vira "pago".
126
+ - Webhook gera `EventoCanonico` e nao confirma nada: reconsulte antes de liquidar.
@@ -0,0 +1,83 @@
1
+ # Banco do Brasil: duvidas em aberto do contrato
2
+
3
+ Fontes usadas, por ordem de confianca:
4
+
5
+ 1. **Doc oficial (developers.bb.com.br / apoio.developers.bb.com.br):** NAO foi
6
+ possivel ler. A pagina de referencia carrega por JavaScript e o WebFetch devolveu
7
+ so "Aguarde...". WebSearch nao trouxe a pagina oficial. Tudo abaixo precisa ser
8
+ conferido contra ela e contra o sandbox antes de producao.
9
+ 2. **Leitura (so como documentacao, sem portar codigo, licenca LGPL) do ACBrBoleto:**
10
+ `WS/ACBrBoletoW_BancoBrasil_API.pas`, `WS/ACBrBoletoRet_BancoBrasil_API.pas`,
11
+ `ACBrBancoBrasil.pas` e a secao 3.1 de `Particularidades.html`. Dela vem: URLs,
12
+ `gw-dev-app-key` em query, paths, nomes de campo do payload e da resposta, datas
13
+ `DD.MM.YYYY`, composicao do `numeroTituloCliente`, tabela de `codigoEstadoTituloCobranca`,
14
+ campos de alteracao (PATCH) e o header `x-bb-portal-devx-cnpj-parceiro`.
15
+ 3. **Fonte de terceiro (wiki CIGAM, via WebSearch):** escopos
16
+ `cobrancas.boletos-requisicao` e `cobrancas.boletos-info`.
17
+
18
+ O adapter nasce com `validado_sandbox = False`.
19
+
20
+ ## Risco do PRD: chave de desenvolvedor e header de parceiro
21
+
22
+ - `gw-dev-app-key` e **query param** em toda chamada de negocio (nao em header),
23
+ inclusive no PATCH e no POST de baixa. O adapter a monta em `_caminho`, mantem fora
24
+ do repr da config e o transporte nunca loga URL.
25
+ - O header `x-bb-portal-devx-cnpj-parceiro` (CNPJ da software house) e opcional
26
+ (`BBConfig.cnpj_parceiro`). Nao se sabe se o BB passara a exigi-lo.
27
+
28
+ ## Duvidas
29
+
30
+ 1. **Autenticacao do token.** O ACBr usa credenciais no corpo no sandbox e Basic
31
+ (`client_id:client_secret`) em producao. O adapter replica isso por padrao
32
+ (`BBConfig.credenciais_no_corpo=None`) e deixa forcar. Confirmar no oficial.
33
+ 2. **Escopos.** Fonte de terceiro, nao oficial. O escopo depende dos servicos marcados
34
+ no app do portal.
35
+ 3. **Nosso numero.** `numeroTituloCliente` = "000" + convenio (7 digitos, zeros a
36
+ esquerda) + nosso numero (10 digitos), pela montagem do ACBr. Para convenio de 6
37
+ digitos o ACBr aplica a mesma regra na API. O modelo canonico nao tem nosso numero:
38
+ quem chama passa `BBConfig.gerar_nosso_numero` ou usa `seu_numero` numerico de ate
39
+ 10 digitos. Quem garante a unicidade da sequencia e o chamador. Convenios de 4 e 5
40
+ digitos (so CNAB) sao recusados.
41
+ 4. **Duplicidade.** Nao se sabe qual codigo o BB devolve para `numeroTituloCliente`
42
+ repetido. So o 409 vira `Duplicado`; a idempotencia real e o cache por
43
+ `chave_idempotencia` (no processo) e o `Orquestrador`.
44
+ 5. **Status do registro.** A resposta traz linha digitavel e codigo de barras, entao o
45
+ adapter devolve `REGISTRADO` (nao `PENDENTE_REGISTRO`). Nao confirmado.
46
+ 6. **Tabela de status.** Mapeados: 1, 2, 3, 4, 5, 8, 9, 13 (REGISTRADO), 6 (LIQUIDADO),
47
+ 7 (BAIXADO), 80 (transitorio, PENDENTE_REGISTRO). **Deliberadamente fora** (levantam
48
+ `Validacao`): 10 (baixado/pago em cartorio), 11 e 12 (liquidado com protesto ou
49
+ cartorio), 14 (em liquidacao), 15 e 21 (agendado), 16 (creditado), 17 (pago em
50
+ cheque), 18 e 19 (pago parcialmente). Sem a doc oficial nao da para saber se cada um
51
+ e dinheiro recebido; liquidar ou baixar por palpite e pior que recusar. Candidatos a
52
+ LIQUIDADO apos confirmacao: 11, 12, 16.
53
+ 7. **Pagamento parcial.** `indicadorPermissaoRecebimentoParcial` nao e enviado. O
54
+ modelo canonico nao tem o conceito.
55
+ 8. **Data de emissao.** O modelo nao tem `dataEmissao`; o adapter usa a data do dia
56
+ (`hoje` injetavel). Confirmar se o BB aceita emissao posterior a hoje ou anterior.
57
+ 9. **Multa.** O BB exige data de inicio; o adapter usa vencimento + 1 dia (suposicao).
58
+ Tipo 2 = percentual. Juros: tipo 2 = taxa mensal. Desconto: tipo 2 = percentual ate
59
+ a data, `dataExpiracao` = vencimento menos `desconto_dias_antes`. Tipos vindos do ACBr.
60
+ 10. **Baixa automatica.** `dias_baixa_automatica` e recusado: a equivalencia com
61
+ `numeroDiasLimiteRecebimento` (prazo de recebimento apos o vencimento) nao e
62
+ certa. Mensagem: o BB limita a 30 caracteres; acima disso o adapter recusa em vez
63
+ de truncar em silencio.
64
+ 11. **CPF/CNPJ como inteiro.** `numeroInscricao` e `cep` vao como numero (como no
65
+ ACBr). CNPJ alfanumerico nao cabe: recusado com `Validacao`. Perguntar ao BB.
66
+ 12. **Pix no boleto (`indicadorPix`).** Configuravel. Quando "S" a resposta de registro
67
+ traz `qrCode.emv/txId/url`, que o adapter expoe em `pix_copia_cola` e `txid`. A
68
+ consulta de detalhe nao traz o Pix (ha `GET /boletos/{id}/pix`, nao implementado), e
69
+ por isso `HIBRIDO` nao e declarada.
70
+ 13. **Baixa.** Resposta com `dataBaixa` e `horarioBaixa`; o adapter devolve `BAIXADO`
71
+ direto, sem reconsultar.
72
+ 14. **Alteracao (PATCH).** Implementados: nova data de vencimento
73
+ (`indicadorNovaDataVencimento` + `alteracaoData`) e abatimento (incluir se o titulo
74
+ nao tem `valorAbatimentoTituloCobranca`, alterar se tem; o adapter consulta antes).
75
+ Cancelar abatimento, desconto, juros, multa, valor nominal, protesto e negativacao
76
+ existem na API mas ficaram fora (o modelo `Instrucao` nao carrega os dados, ou o
77
+ efeito nao esta claro). PROTESTO e NEGATIVACAO levantam `NaoSuportado`.
78
+ 15. **PDF.** Nao ha endpoint de segunda via no que foi lido; `PDF` nao e declarada.
79
+ 16. **Webhook.** Nada no contrato lido. `parse_webhook` levanta `NaoSuportado`.
80
+ 17. **Listagem (`GET /boletos` com filtros)** e a API de consulta por periodo ficaram
81
+ fora da primeira fatia.
82
+ 18. **Homologacao.** O ACBr tem um terceiro ambiente (`api.hm.bb.com.br`); o adapter so
83
+ aceita `sandbox` e `producao`.
@@ -0,0 +1,40 @@
1
+ # PinBank: duvidas em aberto do contrato
2
+
3
+ Fonte unica usada: modulo Odoo `l10n_br_payment_boleto_pinbank` (kmee-odoo-addons,
4
+ branch 16.0). Nao ha documentacao oficial da API no repositorio. O que o modulo nao
5
+ esclarece ficou fora do adapter ou recusado com `Validacao`, em vez de inventado.
6
+
7
+ 1. **Unidade de Juros e Multa.** O modulo envia `{"Valor": int(boleto_interest * 10000)}`
8
+ e `int(boleto_penalty * 10000)`; o vetor de teste usa `Valor: 100`. Nao se sabe se e
9
+ centesimos de percentual, fracao x 10000, nem se juros e ao dia ou ao mes. O adapter
10
+ recusa titulo com multa, juros, desconto, abatimento ou baixa automatica.
11
+ 2. **Desconto, abatimento e baixa automatica.** O modulo nao envia. Mesmo tratamento.
12
+ 3. **Endereco do sacado.** O modulo envia so `street_name` em `Endereco`; numero e
13
+ complemento nao vao em campo algum. O adapter segue o modulo (so o logradouro).
14
+ 4. **CPF/CNPJ e CEP como inteiros.** O modulo envia `int(...)`, o que descarta zeros a
15
+ esquerda (o vetor mostra `Cep: 8473002` na ida e `"08473002"` na volta). O adapter
16
+ segue o modulo. CNPJ alfanumerico nao cabe em inteiro: e recusado com `Validacao`.
17
+ Confirmar com o PinBank se aceitam string e como tratarao o CNPJ alfanumerico.
18
+ 5. **Idempotencia no banco.** O modulo nao manda identificador do cliente. A resposta
19
+ traz `IdentificadorCliente` (nulo no vetor), talvez aceito na geracao. Hoje a garantia
20
+ contra boleto em dobro e do adapter (cache e lock por `chave_idempotencia`, no
21
+ processo) e do `Orquestrador` (repositorio de chaves, entre processos).
22
+ 6. **PDF.** `RetornarBase64` devolve o PDF so na geracao; nao ha endpoint de segunda via
23
+ no modulo e a consulta nao traz `Base64`. O adapter nao declara `PDF`. O PDF recebido
24
+ na geracao fica em `resposta_bruta` mascarado ("***"). Falta um campo no modelo
25
+ canonico para entrega-lo (decisao de produto) ou confirmar endpoint de segunda via.
26
+ 7. **Webhook.** O modulo so faz polling (cron de consulta). Sem contrato: `parse_webhook`
27
+ levanta `NaoSuportado` e `WEBHOOK` nao e declarada.
28
+ 8. **Resposta da baixa.** O modulo ignora o corpo da baixa e reconsulta. O adapter faz
29
+ igual e devolve o estado consultado, que pode ainda nao ser `BAIXADO`.
30
+ 9. **Status.** Mapa extraido do modulo: PENDENTE, REGISTRADO, LIQUIDADO, BAIXA. Se o
31
+ banco tiver outros (vencido, protestado, rejeitado), o adapter levanta `Validacao`
32
+ (nunca assume "pago").
33
+ 10. **Expiracao do token.** O campo e `expire_in` (sem "s"); o autenticador aceita os dois.
34
+ Sem escopo OAuth: o cache e por (conta, sem escopo).
35
+ 11. **Chave AES = senha do usuario**, IV zero, como no modulo. O IV fixo torna o cifrado
36
+ deterministico: a protecao real e o TLS.
37
+ 12. **Erro HTTP com corpo cifrado ou nao.** O modulo le `Message` em claro nos erros;
38
+ o adapter nao decifra respostas >= 400 e as repassa mascaradas.
39
+ 13. **Valor do boleto como `Valor` em centavos e `ValorPago` em centavos** (vetor:
40
+ `Valor: 25875`). `ValorPago` so e lido quando LIQUIDADO.
@@ -0,0 +1,82 @@
1
+ # Pix BACEN generico: duvidas em aberto e quirks
2
+
3
+ Fonte do contrato: OpenAPI oficial da API Pix do BACEN (/cob, /cobv, /webhook,
4
+ /pix/{e2eid}/devolucao), conhecido do padrao publico. O comportamento por PSP
5
+ (host, URL do token, escopos, headers, quirks) foi lido nos fontes do ACBr
6
+ (`ACBrPIXCD`, licenca LGPL) como documentacao, sem portar codigo. Nenhum perfil
7
+ foi testado contra sandbox real: todos nascem com `validado_sandbox = False`.
8
+ O que a leitura nao esclarece ficou de fora ou recusado, nao inventado.
9
+
10
+ ## Perfis
11
+
12
+ | Perfil | Auth | Escopo | mTLS | Quirks aplicados |
13
+ |---|---|---|---|---|
14
+ | inter | form (id+segredo) | sim | sim | nenhum |
15
+ | bb (API v2) | Basic | sim | prod | header `x-bb-portal-devx-cnpj-parceiro`, query `gw-dev-app-key`, alias `textoImagemQRcode` |
16
+ | sicoob | so `client_id` (sandbox: token fixo do portal) | sim | prod | header `client_id`, alias `brcode` -> `pixCopiaECola` |
17
+ | sicredi | Basic | sim | sim | nenhum |
18
+ | itau | form (id+segredo) | nao | prod | header `x-correlationID` (UUID por chamada) |
19
+ | bradesco | Basic, HTTP/1.1 | nao | sim | nenhum |
20
+ | santander | form, `?grant_type` na URL | nao | prod | sandbox cria por POST, baixa (PATCH) em `/api/v2` na producao |
21
+ | efi (GerenciaNet) | Basic + corpo JSON, HTTP/1.1 | nao | sim | header opcional `x-partner-token` |
22
+ | bnb | sem perfil | | | ver abaixo |
23
+
24
+ ## Duvidas
25
+
26
+ 1. **BNB sem perfil.** O ACBr nao tem PSP do Banco do Nordeste. `obter_perfil("bnb")`
27
+ levanta `Validacao`. Falta documentacao do portal do BNB (host, token, escopos).
28
+ 2. **Escopos.** O ACBr pede por padrao cob/cobv/pix/webhook (read e write). Nao ha
29
+ evidencia de qual conjunto cada banco aceita; se o banco recusar um escopo, o
30
+ token falha. Ajustar `escopos` no perfil quando o sandbox responder. Itau, Bradesco,
31
+ Santander e Efi nao mandam escopo (como no ACBr).
32
+ 3. **Idempotencia do `txid`.** O `txid` sai do SHA-256 de `conta|chave_idempotencia`
33
+ (32 hex, dentro de 26-35). A OpenAPI nao diz qual HTTP um PSP devolve para PUT em
34
+ txid existente; o adapter so converte em consulta o 409 (`Duplicado`). Se algum
35
+ banco devolve 400 ou 422, o titulo falha como `Validacao` e o `Orquestrador` (que
36
+ guarda a chave) evita a repeticao. Confirmar por banco.
37
+ 4. **PUT versus POST.** O adapter sempre cria por `PUT /cob(v)/{txid}`. O ACBr converte
38
+ POST em PUT para BB v1 e Santander, e o sandbox do Santander so aceita POST (perfil
39
+ `metodo_criar_sandbox`). `POST /cob` com txid gerado pelo banco nao e usado.
40
+ 5. **BB API v1.** So a v2 tem perfil. A v1 (`api.bb.com.br/pix/v1`) tem `/cobqrcode`
41
+ no sandbox e delimitador `/` antes da query; nao implementado. Confirmar qual
42
+ versao usar.
43
+ 6. **Santander pre-producao e sandbox.** Existe host de pre-producao
44
+ (`trust-pix-h.santander.com.br`), sem perfil. O sandbox devolve JSON fora do padrao
45
+ (lista `cobs[0]`/`pix[0]`); o ACBr corrige, o adapter nao.
46
+ 7. **Itau sandbox.** Exige o header `x-sandbox-token` com o token obtido; o autenticador
47
+ atual nao expoe o token ao adapter. Nao implementado. O fluxo de certificado
48
+ (CSR/renovacao em `/seguranca/v1/certificado`) tambem fica fora.
49
+ 8. **Sicoob em producao.** O ACBr manda so `client_id`, sem segredo, e a identidade vem
50
+ do mTLS. Confirmar que nao ha `client_secret`.
51
+ 9. **HTTP/1.1.** O ACBr forca 1.1 so na chamada de token de Bradesco e Efi. Aqui o
52
+ cliente inteiro desses perfis usa 1.1 (`Transporte(http2=False)`), mais simples e
53
+ mais conservador. Confirmar se so o token precisa.
54
+ 10. **Webhook sem assinatura.** O BACEN protege o callback por mTLS do PSP, nao por HMAC.
55
+ `parse_webhook` nao autentica nada: o receptor precisa validar o certificado do PSP
56
+ (fora da lib) e reconsultar antes de liquidar. A Efi documenta um header para pular
57
+ a checagem de mTLS no cadastro do webhook (`x-skip-mtls-checking`), do conhecimento
58
+ geral e nao da referencia: nao implementado.
59
+ 11. **Webhook sem `txid`.** Pix de QR estatico chega sem `txid`; o adapter ignora (sem
60
+ titulo para baixar). Se o produto quiser conciliar Pix avulso, falta um evento
61
+ canonico proprio. Devolucoes dentro do corpo (`devolucoes`) tambem sao ignoradas.
62
+ 12. **Valor pago parcial e devolucao.** `valor_pago` e a soma de `pix[].valor` da
63
+ consulta, sem descontar devolucoes. Cobranca com `modalidadeAlteracao` nao e
64
+ emitida (valor fixo), entao pagamento parcial nao e esperado.
65
+ 13. **CNPJ alfanumerico.** O adapter envia `cnpj` com o valor normalizado (A-Z e digitos).
66
+ Nao se sabe quais PSPs ja aceitam letras no campo `devedor.cnpj` (o schema antigo
67
+ exigia 14 digitos).
68
+ 14. **Endereco do devedor.** Em `cobv` o adapter manda logradouro (com numero), cidade,
69
+ UF e CEP quando o `Pessoa` tem endereco. Alguns PSPs podem exigir todos os campos;
70
+ nao e validado localmente.
71
+ 15. **Mapeamento de encargos para `cobv`.** Multa = modalidade 2 (percentual); juros =
72
+ modalidade 3 (percentual ao mes, dias corridos); abatimento = modalidade 1 (valor
73
+ fixo); desconto = modalidade 2 (percentual ate a data, `vencimento - dias_antes`).
74
+ O `valorPerc` do abatimento e um valor em reais, nao percentual, apesar do nome do
75
+ campo no BACEN. Juros e multa em outras modalidades (dia util, ao dia) ficam fora.
76
+ 16. **`REMOVIDA_PELO_PSP`.** Mapeada para `BAIXADO`. Pode ser expiracao; se o produto
77
+ quiser distinguir, falta um status canonico.
78
+ 17. **`cob` imediata.** Recusa multa, juros, desconto e abatimento; a validade e
79
+ `expiracao_s` (padrao 86400), nao o vencimento do `Titulo`.
80
+ 18. **Fora do escopo desta entrega:** consulta de Pix por `e2eid` e por periodo, listagem
81
+ de cobrancas, lote `cobv`, `payloadlocation`, recorrencia (`rec`, `cobr`), revisao
82
+ de valor (PATCH com `valor`) e `enviar_instrucao`.
@@ -0,0 +1,76 @@
1
+ # Sicoob (756) API de Cobranca v3: duvidas em aberto
2
+
3
+ `SicoobAdapter.validado_sandbox = False`. Nada foi executado contra o Sicoob.
4
+
5
+ ## Fontes
6
+
7
+ - Referencia de comportamento LIDA (LGPL, nenhum codigo portado, usada so como
8
+ documentacao de endpoints, campos e quirks): ACBr, `ACBrBoletoW_Sicoob_V3.pas`,
9
+ `ACBrBoletoRet_Sicoob_V3.pas`, `ACBrBancoSicoob.pas` e `Particularidades`.
10
+ - Documentacao oficial: o portal `developers.sicoob.com.br` nao entrega a especificacao
11
+ sem login (WebFetch devolveu so o titulo da pagina). Nao foi possivel conferir o swagger.
12
+ - Terceiros lidos: thread do forum ACBr sobre a migracao para a v3 (URLs, mudancas de
13
+ formato) e README do `mangati/sicoob-sdk` (escopo `boletos_inclusao`, `pdfBoleto`).
14
+
15
+ Antes de usar em producao: obter o swagger v3 e rodar a suite contra o sandbox
16
+ (token fixo do sandbox fica no portal, entra em `SicoobConfig.token_sandbox`).
17
+
18
+ ## Duvidas
19
+
20
+ 1. **Corpo do POST /boletos: objeto ou lista?** O ACBr monta um objeto; o swagger v3 pode
21
+ exigir lista. O adapter envia objeto e aceita `resultado` como objeto ou lista (e
22
+ `resultado.boleto` aninhado). Confirmar.
23
+ 2. **Escopos.** So `boletos_inclusao` tem o nome confirmado em fonte de terceiros.
24
+ `boletos_consulta` e `boletos_alteracao` sao suposicao, por isso ficam em
25
+ `SicoobConfig.escopos` (chaves `incluir`, `consultar`, `alterar`).
26
+ 3. **Token sem `client_secret`.** O ACBr envia so `client_id`, `scope`, `grant_type`
27
+ (a autenticacao e o certificado mTLS, que tambem vale na chamada de token). Seguido.
28
+ Token expira em ~300s segundo o SDK de terceiros; o cache usa `expires_in` da resposta.
29
+ 4. **Nosso numero como id.** Consulta, baixa e alteracao usam `nossoNumero` na URL. O
30
+ ACBr calcula e anexa o digito verificador antes de montar a URL; nao se sabe se o
31
+ `nossoNumero` devolvido no registro ja o inclui. O adapter usa o valor devolvido como
32
+ veio. Confirmar.
33
+ 5. **Consulta.** `GET /boletos?numeroCliente&codigoModalidade&nossoNumero`; 204 (sem
34
+ conteudo) vira `Validacao`. Campo de situacao: `situacaoBoleto` com textos como
35
+ "Em Aberto", "Liquidado", "Baixado", "CANCELADO". Lista completa desconhecida.
36
+ 6. **Status.** Mapeados so EM ABERTO, LIQUIDADO, BAIXADO, CANCELADO. `VENCIDO` e
37
+ `EXPIRADO` existem como constantes no ACBr sem uso: ficam fora (viram `Validacao`)
38
+ ate haver contrato. Um boleto vencido e em aberto ainda e cobravel? Confirmar.
39
+ 7. **Valor e data do pagamento.** Nao ha campo numerico: o valor vem de texto em
40
+ `listaHistorico[tipoHistorico=6].descricaoHistorico` apos "R$". O adapter interpreta
41
+ formato pt-BR e, se falhar, devolve `valor_pago=None`. Formato real desconhecido.
42
+ 8. **PDF.** Fora: o ACBr envia `gerarPdf=false` e so le `pdfBoleto` no registro. Existe
43
+ provavelmente um endpoint de segunda via, nao confirmado. `PDF` nao e declarada.
44
+ 9. **Webhook.** Nao ha contrato conhecido para boleto. `WEBHOOK` nao declarada,
45
+ `parse_webhook` levanta `NaoSuportado`. O ACBr usa polling por movimentacao.
46
+ 10. **Movimentacao (fora do escopo).** `POST /boletos/movimentacoes`, consulta da
47
+ solicitacao e download de arquivo zip em base64 (siglas ENTR, PROR, AVENC, VENC,
48
+ LIQUI, BAIX; janela de 2 dias). Util para conciliar em lote; nao implementado.
49
+ 11. **Alteracao.** `PATCH /boletos/{nn}` com `prorrogacaoVencimento`, `abatimento` (e,
50
+ na referencia, `desconto`, `jurosMora`, `multa`, `seuNumero`); protesto em
51
+ `POST /boletos/{nn}/protestos`; negativacao em `/negativacoes` com verbos variados
52
+ (nao implementada). O adapter cobre PRORROGACAO, ABATIMENTO, PROTESTO e BAIXA e devolve
53
+ o estado reconsultado (a API nao devolve dados na alteracao).
54
+ 12. **Desconto.** O modelo canonico traz percentual + dias antes; foi mapeado para
55
+ `tipoDesconto=2` (percentual ate a data informada), data = vencimento - dias. A
56
+ alternativa `5` (percentual por antecipacao em dias corridos) pode ser mais fiel.
57
+ 13. **Multa e juros.** Percentual de multa = `tipoMulta 2`; juros mensal = `tipoJurosMora 2`.
58
+ Data de inicio (`dataMulta`, `dataJurosMora`) = vencimento + 1 dia, escolha do adapter
59
+ (o ACBr reaproveita a data de juros). Sem encargo: `tipoMulta 0`, `tipoJurosMora 3`.
60
+ 14. **Campos obrigatorios nao deduzidos.** `codigoEspecieDocumento` (sem padrao: vem da
61
+ config, tabela do banco), `codigoModalidade` (padrao 1, simples com registro),
62
+ `numeroParcela` (1), `aceite` (false), emissao e distribuicao pelo banco
63
+ (`banco_emite_e_distribui`). `dataEmissao` e a data do dia, injetavel nos testes.
64
+ 15. **Baixa automatica por dias** nao tem campo conhecido: o titulo com
65
+ `dias_baixa_automatica` e recusado. Protesto e negativacao no registro (`codigoProtesto`,
66
+ `numeroDiasProtesto`, `codigoNegativacao`) nao existem no modelo canonico.
67
+ 16. **CPF/CNPJ.** Enviados sem mascara; se a API aceita CNPJ alfanumerico e
68
+ desconhecido. CEP so digitos. Endereco = logradouro + numero (a API nao tem campo
69
+ separado na referencia); complemento nao e enviado.
70
+ 17. **Cota.** O ACBr limita a 2 envios por segundo; adotado como padrao
71
+ (`requisicoes_por_segundo=2.0`). Limite real desconhecido.
72
+ 18. **Erros.** O corpo de erro traz `mensagens[{codigo, mensagem}]` segundo a referencia;
73
+ o adapter nao interpreta (o transporte mascara e repassa). Duplicidade nao
74
+ mapeada para `Duplicado` por falta de codigo conhecido.
75
+ 19. **Hibrido.** `HIBRIDO` e declarada fixa, mas depende de `cadastrar_pix=True`
76
+ (`codigoCadastrarPIX=1`), que exige Pix habilitado na cooperativa. O QR vem em `qrCode`.