bb_api 0.5.3__tar.gz → 0.5.4__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.
- {bb_api-0.5.3 → bb_api-0.5.4}/PKG-INFO +1 -1
- {bb_api-0.5.3 → bb_api-0.5.4}/bb_api/__init__.py +3 -1
- {bb_api-0.5.3 → bb_api-0.5.4}/bb_api/accountability.py +41 -49
- {bb_api-0.5.3 → bb_api-0.5.4}/bb_api/common.py +19 -1
- {bb_api-0.5.3 → bb_api-0.5.4}/bb_api.egg-info/PKG-INFO +1 -1
- {bb_api-0.5.3 → bb_api-0.5.4}/pyproject.toml +1 -1
- {bb_api-0.5.3 → bb_api-0.5.4}/LICENSE +0 -0
- {bb_api-0.5.3 → bb_api-0.5.4}/README.md +0 -0
- {bb_api-0.5.3 → bb_api-0.5.4}/bb_api/gestao_agil.py +0 -0
- {bb_api-0.5.3 → bb_api-0.5.4}/bb_api/sia.py +0 -0
- {bb_api-0.5.3 → bb_api-0.5.4}/bb_api.egg-info/SOURCES.txt +0 -0
- {bb_api-0.5.3 → bb_api-0.5.4}/bb_api.egg-info/dependency_links.txt +0 -0
- {bb_api-0.5.3 → bb_api-0.5.4}/bb_api.egg-info/requires.txt +0 -0
- {bb_api-0.5.3 → bb_api-0.5.4}/bb_api.egg-info/top_level.txt +0 -0
- {bb_api-0.5.3 → bb_api-0.5.4}/setup.cfg +0 -0
|
@@ -4,7 +4,7 @@ from importlib.metadata import PackageNotFoundError, version
|
|
|
4
4
|
try:
|
|
5
5
|
__version__ = version("bb_api")
|
|
6
6
|
except PackageNotFoundError:
|
|
7
|
-
__version__ = "0.5.
|
|
7
|
+
__version__ = "0.5.4"
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
from .common import Ambiente
|
|
@@ -14,6 +14,7 @@ from .accountability import (
|
|
|
14
14
|
AccountabilityV3ControleAPI,
|
|
15
15
|
ExtratoError,
|
|
16
16
|
IntervaloLongoDemaisError,
|
|
17
|
+
RespostaError,
|
|
17
18
|
SemLancamentosError,
|
|
18
19
|
)
|
|
19
20
|
from .sia import (
|
|
@@ -36,6 +37,7 @@ __all__ = [
|
|
|
36
37
|
"CredenciaisNecessariasError",
|
|
37
38
|
"ExtratoError",
|
|
38
39
|
"IntervaloLongoDemaisError",
|
|
40
|
+
"RespostaError",
|
|
39
41
|
"SemLancamentosError",
|
|
40
42
|
"FalhaDownload",
|
|
41
43
|
"ResultadoDownloads",
|
|
@@ -23,23 +23,34 @@ _STATUS_SEM_MOVIMENTO = 404
|
|
|
23
23
|
_SEM_MOVIMENTO_PADRAO = "não há movimento no período consultado"
|
|
24
24
|
|
|
25
25
|
|
|
26
|
-
class
|
|
27
|
-
"""
|
|
26
|
+
class RespostaError(Exception):
|
|
27
|
+
"""Resposta de erro devolvida pela API do Banco do Brasil.
|
|
28
28
|
|
|
29
|
-
Carrega o status HTTP e a mensagem originais
|
|
30
|
-
|
|
29
|
+
Carrega o status HTTP e a mensagem originais junto da ação que falhou. Sem
|
|
30
|
+
eles, um ``404`` de "não há o que devolver", um ``403`` de escopo que falta
|
|
31
|
+
e um ``400`` de parâmetro inválido chegam ao chamador iguais.
|
|
31
32
|
"""
|
|
32
33
|
|
|
33
34
|
status_code: int
|
|
34
35
|
mensagem: str
|
|
35
36
|
|
|
36
|
-
def __init__(self, status_code: int, mensagem: str) -> None:
|
|
37
|
-
|
|
38
|
-
super().__init__(f"Não foi possível reaver o extrato do órgão repassador {detalhe}")
|
|
37
|
+
def __init__(self, acao: str, status_code: int, mensagem: str) -> None:
|
|
38
|
+
super().__init__(f"Não foi possível {acao} (HTTP {status_code}): {mensagem}")
|
|
39
39
|
self.status_code = status_code
|
|
40
40
|
self.mensagem = mensagem
|
|
41
41
|
|
|
42
42
|
|
|
43
|
+
class ExtratoError(RespostaError):
|
|
44
|
+
"""Erro devolvido pela API ao consultar o extrato do órgão repassador.
|
|
45
|
+
|
|
46
|
+
Carrega o status HTTP e a mensagem originais do Banco do Brasil, porque a
|
|
47
|
+
API usa ``400`` tanto para falha de verdade quanto para situações normais.
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
def __init__(self, status_code: int, mensagem: str) -> None:
|
|
51
|
+
super().__init__("reaver o extrato do órgão repassador", status_code, mensagem)
|
|
52
|
+
|
|
53
|
+
|
|
43
54
|
class SemLancamentosError(ExtratoError):
|
|
44
55
|
"""A conta não tem lançamento nenhum no período consultado.
|
|
45
56
|
|
|
@@ -99,6 +110,11 @@ def _mensagem_da_lista_de_erros(campos: dict[str, object]) -> str:
|
|
|
99
110
|
return ""
|
|
100
111
|
|
|
101
112
|
|
|
113
|
+
def _erro(acao: str, res: requests.Response) -> RespostaError:
|
|
114
|
+
"""Erro de uma resposta não-200, com a ação que falhou e o que o BB disse."""
|
|
115
|
+
return RespostaError(acao, res.status_code, _mensagem_de_erro(res))
|
|
116
|
+
|
|
117
|
+
|
|
102
118
|
def _erro_extrato(res: requests.Response) -> ExtratoError:
|
|
103
119
|
mensagem = _mensagem_de_erro(res)
|
|
104
120
|
normalizada = mensagem.casefold()
|
|
@@ -235,7 +251,7 @@ class _AccountabilityV3BaseAPI:
|
|
|
235
251
|
)
|
|
236
252
|
|
|
237
253
|
if res.status_code != 200:
|
|
238
|
-
raise
|
|
254
|
+
raise _erro("adquirir as novas credenciais de acesso", res)
|
|
239
255
|
|
|
240
256
|
data = common.parse_json_object(res)
|
|
241
257
|
self._access_token = cast("str", data["access_token"])
|
|
@@ -266,9 +282,7 @@ class _AccountabilityV3BaseAPI:
|
|
|
266
282
|
)
|
|
267
283
|
|
|
268
284
|
if res.status_code != 200:
|
|
269
|
-
raise
|
|
270
|
-
"Não foi possível listar as categorias do programa de governo."
|
|
271
|
-
)
|
|
285
|
+
raise _erro("listar as agências próximas", res)
|
|
272
286
|
|
|
273
287
|
res = common.parse_json_object(res)
|
|
274
288
|
return common.handle_results(
|
|
@@ -411,7 +425,7 @@ class AccountabilityV3RepasseAPI(_AccountabilityV3BaseAPI):
|
|
|
411
425
|
)
|
|
412
426
|
|
|
413
427
|
if res.status_code != 200:
|
|
414
|
-
raise
|
|
428
|
+
raise _erro("reaver o documento de despesa do programa de governo", res)
|
|
415
429
|
|
|
416
430
|
res = common.parse_json_object(res)
|
|
417
431
|
|
|
@@ -542,7 +556,7 @@ class AccountabilityV3RepasseAPI(_AccountabilityV3BaseAPI):
|
|
|
542
556
|
)
|
|
543
557
|
|
|
544
558
|
if res.status_code != 200:
|
|
545
|
-
raise
|
|
559
|
+
raise _erro("reaver o documento de despesa da prestação de contas", res)
|
|
546
560
|
|
|
547
561
|
res = common.parse_json_object(res)
|
|
548
562
|
|
|
@@ -674,7 +688,7 @@ class AccountabilityV3RepasseAPI(_AccountabilityV3BaseAPI):
|
|
|
674
688
|
)
|
|
675
689
|
|
|
676
690
|
if res.status_code != 200:
|
|
677
|
-
raise
|
|
691
|
+
raise _erro("reaver o extrato de subtransações do programa de governo", res)
|
|
678
692
|
|
|
679
693
|
res = common.parse_json_object(res)
|
|
680
694
|
|
|
@@ -974,9 +988,7 @@ class AccountabilityV3RepasseAPI(_AccountabilityV3BaseAPI):
|
|
|
974
988
|
)
|
|
975
989
|
|
|
976
990
|
if res.status_code != 200:
|
|
977
|
-
raise
|
|
978
|
-
"Não foi possível listar as categorias do programa de governo."
|
|
979
|
-
)
|
|
991
|
+
raise _erro("listar os lançamentos atualizados do programa de governo", res)
|
|
980
992
|
|
|
981
993
|
res = common.parse_json_object(res)
|
|
982
994
|
return common.handle_results(
|
|
@@ -1017,9 +1029,7 @@ class AccountabilityV3RepasseAPI(_AccountabilityV3BaseAPI):
|
|
|
1017
1029
|
)
|
|
1018
1030
|
|
|
1019
1031
|
if res.status_code != 200:
|
|
1020
|
-
raise
|
|
1021
|
-
"Não foi possível listar as categorias do programa de governo."
|
|
1022
|
-
)
|
|
1032
|
+
raise _erro("listar os sublançamentos atualizados do programa de governo", res)
|
|
1023
1033
|
|
|
1024
1034
|
res = common.parse_json_object(res)
|
|
1025
1035
|
return common.handle_results(
|
|
@@ -1053,9 +1063,7 @@ class AccountabilityV3RepasseAPI(_AccountabilityV3BaseAPI):
|
|
|
1053
1063
|
)
|
|
1054
1064
|
|
|
1055
1065
|
if res.status_code != 200:
|
|
1056
|
-
raise
|
|
1057
|
-
"Não foi possível listar as categorias do programa de governo."
|
|
1058
|
-
)
|
|
1066
|
+
raise _erro("listar as categorias do programa de governo", res)
|
|
1059
1067
|
|
|
1060
1068
|
res = common.parse_json_object(res)
|
|
1061
1069
|
return common.handle_results(
|
|
@@ -1086,9 +1094,7 @@ class AccountabilityV3RepasseAPI(_AccountabilityV3BaseAPI):
|
|
|
1086
1094
|
)
|
|
1087
1095
|
|
|
1088
1096
|
if res.status_code != 200:
|
|
1089
|
-
raise
|
|
1090
|
-
"Não foi possível listar as categorias do programa de governo."
|
|
1091
|
-
)
|
|
1097
|
+
raise _erro("reaver o saldo das aplicações financeiras", res)
|
|
1092
1098
|
|
|
1093
1099
|
res = common.parse_json_object(res)
|
|
1094
1100
|
return common.handle_results(
|
|
@@ -1125,9 +1131,7 @@ class AccountabilityV3RepasseAPI(_AccountabilityV3BaseAPI):
|
|
|
1125
1131
|
)
|
|
1126
1132
|
|
|
1127
1133
|
if res.status_code != 200:
|
|
1128
|
-
raise
|
|
1129
|
-
"Não foi possível listar as categorias do programa de governo."
|
|
1130
|
-
)
|
|
1134
|
+
raise _erro("reaver o saldo da conta corrente", res)
|
|
1131
1135
|
|
|
1132
1136
|
res = common.parse_json_object(res)
|
|
1133
1137
|
|
|
@@ -1173,9 +1177,7 @@ class AccountabilityV3RepasseAPI(_AccountabilityV3BaseAPI):
|
|
|
1173
1177
|
)
|
|
1174
1178
|
|
|
1175
1179
|
if res.status_code not in [200, 201]:
|
|
1176
|
-
raise
|
|
1177
|
-
"Não foi possível listar as categorias do programa de governo."
|
|
1178
|
-
)
|
|
1180
|
+
raise _erro("categorizar a despesa do lançamento a crédito", res)
|
|
1179
1181
|
|
|
1180
1182
|
res = common.parse_json_object(res)
|
|
1181
1183
|
return common.handle_results(
|
|
@@ -1222,9 +1224,7 @@ class AccountabilityV3RepasseAPI(_AccountabilityV3BaseAPI):
|
|
|
1222
1224
|
)
|
|
1223
1225
|
|
|
1224
1226
|
if res.status_code not in [200, 201]:
|
|
1225
|
-
raise
|
|
1226
|
-
"Não foi possível listar as categorias do programa de governo."
|
|
1227
|
-
)
|
|
1227
|
+
raise _erro("identificar o lançamento a crédito", res)
|
|
1228
1228
|
|
|
1229
1229
|
res = common.parse_json_object(res)
|
|
1230
1230
|
return common.handle_results(
|
|
@@ -1255,9 +1255,7 @@ class AccountabilityV3RepasseAPI(_AccountabilityV3BaseAPI):
|
|
|
1255
1255
|
)
|
|
1256
1256
|
|
|
1257
1257
|
if res.status_code not in [200, 201]:
|
|
1258
|
-
raise
|
|
1259
|
-
"Não foi possível listar as categorias do programa de governo."
|
|
1260
|
-
)
|
|
1258
|
+
raise _erro("excluir a identificação do lançamento a crédito", res)
|
|
1261
1259
|
|
|
1262
1260
|
res = common.parse_json_object(res)
|
|
1263
1261
|
return common.handle_results(
|
|
@@ -1286,9 +1284,7 @@ class AccountabilityV3RepasseAPI(_AccountabilityV3BaseAPI):
|
|
|
1286
1284
|
)
|
|
1287
1285
|
|
|
1288
1286
|
if res.status_code != 200:
|
|
1289
|
-
raise
|
|
1290
|
-
"Não foi possível listar as categorias do programa de governo."
|
|
1291
|
-
)
|
|
1287
|
+
raise _erro("listar as identificações dos lançamentos a débito", res)
|
|
1292
1288
|
|
|
1293
1289
|
res = common.parse_json_object(res)
|
|
1294
1290
|
return common.handle_results(
|
|
@@ -1431,7 +1427,7 @@ class AccountabilityV3ControleAPI(_AccountabilityV3BaseAPI):
|
|
|
1431
1427
|
)
|
|
1432
1428
|
|
|
1433
1429
|
if res.status_code != 200:
|
|
1434
|
-
raise
|
|
1430
|
+
raise _erro("reaver o documento de despesa do programa de governo", res)
|
|
1435
1431
|
|
|
1436
1432
|
res = common.parse_json_object(res)
|
|
1437
1433
|
|
|
@@ -1562,7 +1558,7 @@ class AccountabilityV3ControleAPI(_AccountabilityV3BaseAPI):
|
|
|
1562
1558
|
)
|
|
1563
1559
|
|
|
1564
1560
|
if res.status_code != 200:
|
|
1565
|
-
raise
|
|
1561
|
+
raise _erro("reaver o documento de despesa da prestação de contas", res)
|
|
1566
1562
|
|
|
1567
1563
|
res = common.parse_json_object(res)
|
|
1568
1564
|
|
|
@@ -1688,9 +1684,7 @@ class AccountabilityV3ControleAPI(_AccountabilityV3BaseAPI):
|
|
|
1688
1684
|
)
|
|
1689
1685
|
|
|
1690
1686
|
if res.status_code != 200:
|
|
1691
|
-
raise
|
|
1692
|
-
"Não foi possível listar as categorias do programa de governo."
|
|
1693
|
-
)
|
|
1687
|
+
raise _erro("reaver o extrato de subtransações do programa de governo", res)
|
|
1694
1688
|
|
|
1695
1689
|
res = common.parse_json_object(res)
|
|
1696
1690
|
return common.handle_results(
|
|
@@ -1978,9 +1972,7 @@ class AccountabilityV3ControleAPI(_AccountabilityV3BaseAPI):
|
|
|
1978
1972
|
)
|
|
1979
1973
|
|
|
1980
1974
|
if res.status_code != 200:
|
|
1981
|
-
raise
|
|
1982
|
-
"Não foi possível listar as categorias do programa de governo."
|
|
1983
|
-
)
|
|
1975
|
+
raise _erro("listar as contas correntes do órgão de controle", res)
|
|
1984
1976
|
|
|
1985
1977
|
res = common.parse_json_object(res)
|
|
1986
1978
|
return common.handle_results(
|
|
@@ -60,9 +60,27 @@ def handle_numeric_string_with_symbols(v: str) -> str:
|
|
|
60
60
|
return re.sub(r"\D", "", v)
|
|
61
61
|
|
|
62
62
|
|
|
63
|
+
def _data_de_texto(texto: str) -> datetime:
|
|
64
|
+
"""Interpreta uma data em ISO ou em dd/mm/aaaa.
|
|
65
|
+
|
|
66
|
+
A API devolve os dois formatos, e o valor de uma resposta costuma virar
|
|
67
|
+
parâmetro da consulta seguinte: o ``bookingDate`` do extrato chega em
|
|
68
|
+
dd/mm/aaaa e é o que identifica o documento de despesa daquela transação.
|
|
69
|
+
"""
|
|
70
|
+
formatos = ("%Y-%m-%d", "%d/%m/%Y")
|
|
71
|
+
for formato in formatos:
|
|
72
|
+
try:
|
|
73
|
+
return datetime.strptime(texto, formato)
|
|
74
|
+
except ValueError:
|
|
75
|
+
continue
|
|
76
|
+
|
|
77
|
+
aceitos = " ou ".join(formatos)
|
|
78
|
+
raise ValueError(f"A data '{texto}' não está em {aceitos}.")
|
|
79
|
+
|
|
80
|
+
|
|
63
81
|
def handle_dates(v: DateLike) -> str:
|
|
64
82
|
if isinstance(v, str):
|
|
65
|
-
dt =
|
|
83
|
+
dt = _data_de_texto(v)
|
|
66
84
|
elif isinstance(v, datetime):
|
|
67
85
|
dt = v
|
|
68
86
|
else:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|