bb_api 0.5.1__tar.gz → 0.5.2__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.1 → bb_api-0.5.2}/PKG-INFO +1 -1
- {bb_api-0.5.1 → bb_api-0.5.2}/bb_api/__init__.py +1 -1
- {bb_api-0.5.1 → bb_api-0.5.2}/bb_api/accountability.py +81 -20
- {bb_api-0.5.1 → bb_api-0.5.2}/bb_api/common.py +1 -1
- {bb_api-0.5.1 → bb_api-0.5.2}/bb_api.egg-info/PKG-INFO +1 -1
- {bb_api-0.5.1 → bb_api-0.5.2}/pyproject.toml +1 -1
- {bb_api-0.5.1 → bb_api-0.5.2}/LICENSE +0 -0
- {bb_api-0.5.1 → bb_api-0.5.2}/README.md +0 -0
- {bb_api-0.5.1 → bb_api-0.5.2}/bb_api/gestao_agil.py +0 -0
- {bb_api-0.5.1 → bb_api-0.5.2}/bb_api/sia.py +0 -0
- {bb_api-0.5.1 → bb_api-0.5.2}/bb_api.egg-info/SOURCES.txt +0 -0
- {bb_api-0.5.1 → bb_api-0.5.2}/bb_api.egg-info/dependency_links.txt +0 -0
- {bb_api-0.5.1 → bb_api-0.5.2}/bb_api.egg-info/requires.txt +0 -0
- {bb_api-0.5.1 → bb_api-0.5.2}/bb_api.egg-info/top_level.txt +0 -0
- {bb_api-0.5.1 → bb_api-0.5.2}/setup.cfg +0 -0
|
@@ -19,6 +19,9 @@ MAX_DIAS_EXTRATO = 31
|
|
|
19
19
|
_ERRO_SEM_LANCAMENTOS = "não existem lançamentos"
|
|
20
20
|
_ERRO_INTERVALO_LONGO = "maior do que 31 dias"
|
|
21
21
|
|
|
22
|
+
_STATUS_SEM_MOVIMENTO = 404
|
|
23
|
+
_SEM_MOVIMENTO_PADRAO = "não há movimento no período consultado"
|
|
24
|
+
|
|
22
25
|
|
|
23
26
|
class ExtratoError(Exception):
|
|
24
27
|
"""Erro devolvido pela API ao consultar o extrato do órgão repassador.
|
|
@@ -43,6 +46,10 @@ class SemLancamentosError(ExtratoError):
|
|
|
43
46
|
A API responde ``400`` nesse caso, e não ``200`` com uma lista vazia, então
|
|
44
47
|
esse resultado normal chega como erro e precisa ser separado de uma falha —
|
|
45
48
|
senão uma conta parada vira indistinguível de uma consulta quebrada.
|
|
49
|
+
|
|
50
|
+
Nos extratos de aplicação (fundos de investimento e poupança) a mesma
|
|
51
|
+
situação chega como ``404`` de corpo vazio, e cobre tanto o mês sem
|
|
52
|
+
movimento quanto a aplicação que a conta não possui.
|
|
46
53
|
"""
|
|
47
54
|
|
|
48
55
|
|
|
@@ -64,9 +71,34 @@ def _mensagem_de_erro(res: requests.Response) -> str:
|
|
|
64
71
|
valor = campos.get(chave)
|
|
65
72
|
if isinstance(valor, str) and valor:
|
|
66
73
|
return valor
|
|
74
|
+
|
|
75
|
+
detalhada = _mensagem_da_lista_de_erros(campos)
|
|
76
|
+
if detalhada:
|
|
77
|
+
return detalhada
|
|
67
78
|
return res.text.strip()
|
|
68
79
|
|
|
69
80
|
|
|
81
|
+
def _mensagem_da_lista_de_erros(campos: dict[str, object]) -> str:
|
|
82
|
+
"""Extrai a mensagem de um corpo no formato ``{"erros": [{...}]}``.
|
|
83
|
+
|
|
84
|
+
``menssagem``, com dois esses, é como o Banco do Brasil escreve a chave
|
|
85
|
+
nesse formato de erro.
|
|
86
|
+
"""
|
|
87
|
+
for chave in ("erros", "errors"):
|
|
88
|
+
itens = campos.get(chave)
|
|
89
|
+
if not isinstance(itens, list) or not itens:
|
|
90
|
+
continue
|
|
91
|
+
primeiro = cast("list[object]", itens)[0]
|
|
92
|
+
if not isinstance(primeiro, dict):
|
|
93
|
+
continue
|
|
94
|
+
item = cast("dict[str, object]", primeiro)
|
|
95
|
+
for interna in ("menssagem", "mensagem", "message", "descricao"):
|
|
96
|
+
valor = item.get(interna)
|
|
97
|
+
if isinstance(valor, str) and valor:
|
|
98
|
+
return valor
|
|
99
|
+
return ""
|
|
100
|
+
|
|
101
|
+
|
|
70
102
|
def _erro_extrato(res: requests.Response) -> ExtratoError:
|
|
71
103
|
mensagem = _mensagem_de_erro(res)
|
|
72
104
|
normalizada = mensagem.casefold()
|
|
@@ -77,6 +109,19 @@ def _erro_extrato(res: requests.Response) -> ExtratoError:
|
|
|
77
109
|
return ExtratoError(res.status_code, mensagem)
|
|
78
110
|
|
|
79
111
|
|
|
112
|
+
def _erro_extrato_aplicacao(res: requests.Response) -> ExtratoError:
|
|
113
|
+
"""Classifica o erro dos extratos de fundo de investimento e de poupança.
|
|
114
|
+
|
|
115
|
+
Esses extratos usam ``404`` de corpo vazio para "não há o que devolver" —
|
|
116
|
+
mês sem movimento ou aplicação que a conta não tem —, então esse status
|
|
117
|
+
vira :class:`SemLancamentosError` em vez de falha.
|
|
118
|
+
"""
|
|
119
|
+
if res.status_code == _STATUS_SEM_MOVIMENTO:
|
|
120
|
+
mensagem = _mensagem_de_erro(res) or _SEM_MOVIMENTO_PADRAO
|
|
121
|
+
return SemLancamentosError(res.status_code, mensagem)
|
|
122
|
+
return _erro_extrato(res)
|
|
123
|
+
|
|
124
|
+
|
|
80
125
|
class _AccountabilityV3BaseAPI:
|
|
81
126
|
_app_key: str
|
|
82
127
|
_client_id: str
|
|
@@ -685,6 +730,15 @@ class AccountabilityV3RepasseAPI(_AccountabilityV3BaseAPI):
|
|
|
685
730
|
mes: int,
|
|
686
731
|
ano: int,
|
|
687
732
|
) -> pd.DataFrame:
|
|
733
|
+
"""Reaver o extrato mensal de um fundo de investimento da conta.
|
|
734
|
+
|
|
735
|
+
``fundo_investimento_id`` é o ``grupoAtivo`` que
|
|
736
|
+
:meth:`get_saldo_aplicacoes_financeiras` devolve em cada operação — não
|
|
737
|
+
o ``codigo`` nem a ``modalidade``, que respondem ``404``.
|
|
738
|
+
|
|
739
|
+
Levanta :class:`SemLancamentosError` quando o mês não tem movimento ou
|
|
740
|
+
a conta não tem esse fundo.
|
|
741
|
+
"""
|
|
688
742
|
access_token = self._get_access_token()
|
|
689
743
|
|
|
690
744
|
res = requests.request(
|
|
@@ -699,9 +753,7 @@ class AccountabilityV3RepasseAPI(_AccountabilityV3BaseAPI):
|
|
|
699
753
|
)
|
|
700
754
|
|
|
701
755
|
if res.status_code != 200:
|
|
702
|
-
raise
|
|
703
|
-
"Não foi possível listar as categorias do programa de governo."
|
|
704
|
-
)
|
|
756
|
+
raise _erro_extrato_aplicacao(res)
|
|
705
757
|
|
|
706
758
|
res = common.parse_json_object(res)
|
|
707
759
|
extrato = cast("dict[str, object]", res["extrato"])
|
|
@@ -711,7 +763,7 @@ class AccountabilityV3RepasseAPI(_AccountabilityV3BaseAPI):
|
|
|
711
763
|
main_list="listaLancamentosExtrato",
|
|
712
764
|
insertables=[
|
|
713
765
|
"numeroAgenciaRecebedora",
|
|
714
|
-
"
|
|
766
|
+
"digitoVerificadoraContaRecebedora",
|
|
715
767
|
"numeroContaCorrenteRecebedora",
|
|
716
768
|
"numeroDigitoVerificadorContaCorrenteRecebedora",
|
|
717
769
|
"nomeClienteRecebedor",
|
|
@@ -719,7 +771,6 @@ class AccountabilityV3RepasseAPI(_AccountabilityV3BaseAPI):
|
|
|
719
771
|
"CNPJFundoInvestimento",
|
|
720
772
|
"valorCotaExtrato",
|
|
721
773
|
"dataAfericaoValorCota",
|
|
722
|
-
"ultimaCotacaoCota",
|
|
723
774
|
"dataUltimaCotacaoCota",
|
|
724
775
|
"sinalRentabilidadeMes",
|
|
725
776
|
"valorRentabilidadeMes",
|
|
@@ -758,7 +809,7 @@ class AccountabilityV3RepasseAPI(_AccountabilityV3BaseAPI):
|
|
|
758
809
|
],
|
|
759
810
|
rename_dict={
|
|
760
811
|
"numeroAgenciaRecebedora": "Número Agência Recebedora",
|
|
761
|
-
"
|
|
812
|
+
"digitoVerificadoraContaRecebedora": "Dígito Verificador Conta Recebedora",
|
|
762
813
|
"numeroContaCorrenteRecebedora": "Número Conta Corrente Recebedora",
|
|
763
814
|
"numeroDigitoVerificadorContaCorrenteRecebedora": "Número Dígito Verificador Conta Corrente Recebedora",
|
|
764
815
|
"nomeClienteRecebedor": "Nome Cliente Recebedor",
|
|
@@ -766,7 +817,6 @@ class AccountabilityV3RepasseAPI(_AccountabilityV3BaseAPI):
|
|
|
766
817
|
"CNPJFundoInvestimento": " CNPJ Fundo Investimento",
|
|
767
818
|
"valorCotaExtrato": "Valor Cota Extrato",
|
|
768
819
|
"dataAfericaoValorCota": "Data Afericão Valor Cota",
|
|
769
|
-
"ultimaCotacaoCota": "Última Cotação Cota",
|
|
770
820
|
"dataUltimaCotacaoCota": "Data Última Cotação Cota",
|
|
771
821
|
"sinalRentabilidadeMes": "Sinal Rentabilidade Mês",
|
|
772
822
|
"valorRentabilidadeMes": "Valor Rentabilidade Mês",
|
|
@@ -837,6 +887,12 @@ class AccountabilityV3RepasseAPI(_AccountabilityV3BaseAPI):
|
|
|
837
887
|
mes: int,
|
|
838
888
|
ano: int,
|
|
839
889
|
) -> pd.DataFrame:
|
|
890
|
+
"""Reaver o extrato mensal de uma variação de poupança da conta.
|
|
891
|
+
|
|
892
|
+
Levanta :class:`SemLancamentosError` quando não há o que devolver e
|
|
893
|
+
:class:`ExtratoError` quando a variação não existe — nesse caso a API
|
|
894
|
+
responde ``400`` dizendo que o número da variação não é válido.
|
|
895
|
+
"""
|
|
840
896
|
access_token = self._get_access_token()
|
|
841
897
|
|
|
842
898
|
res = requests.request(
|
|
@@ -851,9 +907,7 @@ class AccountabilityV3RepasseAPI(_AccountabilityV3BaseAPI):
|
|
|
851
907
|
)
|
|
852
908
|
|
|
853
909
|
if res.status_code != 200:
|
|
854
|
-
raise
|
|
855
|
-
"Não foi possível listar as categorias do programa de governo."
|
|
856
|
-
)
|
|
910
|
+
raise _erro_extrato_aplicacao(res)
|
|
857
911
|
|
|
858
912
|
res = common.parse_json_object(res)
|
|
859
913
|
return common.handle_results(
|
|
@@ -1689,6 +1743,14 @@ class AccountabilityV3ControleAPI(_AccountabilityV3BaseAPI):
|
|
|
1689
1743
|
mes: int,
|
|
1690
1744
|
ano: int,
|
|
1691
1745
|
) -> pd.DataFrame:
|
|
1746
|
+
"""Reaver o extrato mensal de um fundo de investimento da conta.
|
|
1747
|
+
|
|
1748
|
+
``fundo_investimento_id`` é o ``grupoAtivo`` da operação no saldo de
|
|
1749
|
+
aplicações financeiras, não o ``codigo`` nem a ``modalidade``.
|
|
1750
|
+
|
|
1751
|
+
Levanta :class:`SemLancamentosError` quando o mês não tem movimento ou
|
|
1752
|
+
a conta não tem esse fundo.
|
|
1753
|
+
"""
|
|
1692
1754
|
access_token = self._get_access_token()
|
|
1693
1755
|
|
|
1694
1756
|
res = requests.request(
|
|
@@ -1703,9 +1765,7 @@ class AccountabilityV3ControleAPI(_AccountabilityV3BaseAPI):
|
|
|
1703
1765
|
)
|
|
1704
1766
|
|
|
1705
1767
|
if res.status_code != 200:
|
|
1706
|
-
raise
|
|
1707
|
-
"Não foi possível listar as categorias do programa de governo."
|
|
1708
|
-
)
|
|
1768
|
+
raise _erro_extrato_aplicacao(res)
|
|
1709
1769
|
|
|
1710
1770
|
res = common.parse_json_object(res)
|
|
1711
1771
|
extrato = cast("dict[str, object]", res["extrato"])
|
|
@@ -1715,7 +1775,7 @@ class AccountabilityV3ControleAPI(_AccountabilityV3BaseAPI):
|
|
|
1715
1775
|
main_list="listaLancamentosExtrato",
|
|
1716
1776
|
insertables=[
|
|
1717
1777
|
"numeroAgenciaRecebedora",
|
|
1718
|
-
"
|
|
1778
|
+
"digitoVerificadoraContaRecebedora",
|
|
1719
1779
|
"numeroContaCorrenteRecebedora",
|
|
1720
1780
|
"numeroDigitoVerificadorContaCorrenteRecebedora",
|
|
1721
1781
|
"nomeClienteRecebedor",
|
|
@@ -1723,7 +1783,6 @@ class AccountabilityV3ControleAPI(_AccountabilityV3BaseAPI):
|
|
|
1723
1783
|
"CNPJFundoInvestimento",
|
|
1724
1784
|
"valorCotaExtrato",
|
|
1725
1785
|
"dataAfericaoValorCota",
|
|
1726
|
-
"ultimaCotacaoCota",
|
|
1727
1786
|
"dataUltimaCotacaoCota",
|
|
1728
1787
|
"sinalRentabilidadeMes",
|
|
1729
1788
|
"valorRentabilidadeMes",
|
|
@@ -1762,7 +1821,7 @@ class AccountabilityV3ControleAPI(_AccountabilityV3BaseAPI):
|
|
|
1762
1821
|
],
|
|
1763
1822
|
rename_dict={
|
|
1764
1823
|
"numeroAgenciaRecebedora": "Número Agência Recebedora",
|
|
1765
|
-
"
|
|
1824
|
+
"digitoVerificadoraContaRecebedora": "Dígito Verificador Conta Recebedora",
|
|
1766
1825
|
"numeroContaCorrenteRecebedora": "Número Conta Corrente Recebedora",
|
|
1767
1826
|
"numeroDigitoVerificadorContaCorrenteRecebedora": "Número Dígito Verificador Conta Corrente Recebedora",
|
|
1768
1827
|
"nomeClienteRecebedor": "Nome Cliente Recebedor",
|
|
@@ -1770,7 +1829,6 @@ class AccountabilityV3ControleAPI(_AccountabilityV3BaseAPI):
|
|
|
1770
1829
|
"CNPJFundoInvestimento": " CNPJ Fundo Investimento",
|
|
1771
1830
|
"valorCotaExtrato": "Valor Cota Extrato",
|
|
1772
1831
|
"dataAfericaoValorCota": "Data Afericão Valor Cota",
|
|
1773
|
-
"ultimaCotacaoCota": "Última Cotação Cota",
|
|
1774
1832
|
"dataUltimaCotacaoCota": "Data Última Cotação Cota",
|
|
1775
1833
|
"sinalRentabilidadeMes": "Sinal Rentabilidade Mês",
|
|
1776
1834
|
"valorRentabilidadeMes": "Valor Rentabilidade Mês",
|
|
@@ -1840,6 +1898,11 @@ class AccountabilityV3ControleAPI(_AccountabilityV3BaseAPI):
|
|
|
1840
1898
|
variacao_poupanca: str,
|
|
1841
1899
|
codigo_variacao: int,
|
|
1842
1900
|
) -> pd.DataFrame:
|
|
1901
|
+
"""Reaver o extrato de uma variação de poupança da conta.
|
|
1902
|
+
|
|
1903
|
+
Levanta :class:`SemLancamentosError` quando não há o que devolver e
|
|
1904
|
+
:class:`ExtratoError` quando a variação não existe.
|
|
1905
|
+
"""
|
|
1843
1906
|
access_token = self._get_access_token()
|
|
1844
1907
|
|
|
1845
1908
|
res = requests.request(
|
|
@@ -1853,9 +1916,7 @@ class AccountabilityV3ControleAPI(_AccountabilityV3BaseAPI):
|
|
|
1853
1916
|
)
|
|
1854
1917
|
|
|
1855
1918
|
if res.status_code != 200:
|
|
1856
|
-
raise
|
|
1857
|
-
"Não foi possível listar as categorias do programa de governo."
|
|
1858
|
-
)
|
|
1919
|
+
raise _erro_extrato_aplicacao(res)
|
|
1859
1920
|
|
|
1860
1921
|
res = common.parse_json_object(res)
|
|
1861
1922
|
return common.handle_results(
|
|
@@ -91,7 +91,7 @@ def handle_results(
|
|
|
91
91
|
|
|
92
92
|
if insertables is not None:
|
|
93
93
|
for insertable in insertables:
|
|
94
|
-
df[insertable] = cast("Scalar", record
|
|
94
|
+
df[insertable] = cast("Scalar", record.get(insertable))
|
|
95
95
|
|
|
96
96
|
if explodeables is not None:
|
|
97
97
|
for explodeable in explodeables:
|
|
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
|