Skip to content

Commit

Permalink
Merge pull request #9 from lucasrcezimbra/develop
Browse files Browse the repository at this point in the history
0.0.4
  • Loading branch information
lucasrcezimbra authored Oct 23, 2022
2 parents e99f197 + 7ab8bbf commit 40d4e27
Show file tree
Hide file tree
Showing 14 changed files with 340 additions and 125 deletions.
19 changes: 17 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,21 @@
# Changelog


## (unreleased)
## 0.0.4 (2022-10-23)
- Add High Level API
- Fix Read the Docs
- Fix Coveralls

* First release on PyPI.

## 0.0.3 (2022-10-15)
- Add Inter.get_balance
- Improve docs


## 0.0.2 (2022-10-15)
- Fix build


## 0.0.1 (2022-10-15)
- First PyPI version
* authentication and get_statements
16 changes: 15 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,24 @@ pip install bancointer

## How to Use

### High-level API
```python
from inter import Inter


inter = Inter.from_credentials(
"YOUR_CLIENT_ID",
"YOUR_CLIENT_SECRET"
'/path/to/certificado.crt',
'/path/to/chave.key',
)
```

### Low-level API
```python
from datetime import date

from inter import Inter
from inter import Client as Inter


inter = Inter(
Expand Down
2 changes: 1 addition & 1 deletion docs/modules.rst → docs/api.rst
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
inter
API
=====

.. toctree::
Expand Down
2 changes: 1 addition & 1 deletion docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Welcome to Banco Inter's documentation!
:caption: Contents:

readme
modules
api
changelog

Indices and tables
Expand Down
10 changes: 1 addition & 9 deletions docs/inter.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,10 @@ inter package
Submodules
----------

inter.inter module
------------------

.. automodule:: inter.inter
:members:
:undoc-members:
:show-inheritance:

Module contents
---------------

.. automodule:: inter
:members:
:members: Inter, Client, Operation
:undoc-members:
:show-inheritance:
5 changes: 3 additions & 2 deletions inter/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from inter.inter import URL, Inter # noqa
from inter._client import Client # noqa
from inter._inter import Inter, Operation # noqa

__author__ = """Lucas Rangel Cezimbra"""
__email__ = 'lucas@cezimbra.tec.br'
__version__ = '0.0.3'
__version__ = '0.0.4'
2 changes: 1 addition & 1 deletion inter/inter.py → inter/_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class URL:
BALANCE = BASE + 'banking/v2/saldo'


class Inter:
class Client:
def __init__(self, client_id, client_secret, cert_path, key_path):
self.client_id = client_id
self.client_secret = client_secret
Expand Down
88 changes: 88 additions & 0 deletions inter/_inter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
from datetime import date, datetime
from decimal import Decimal

from attrs import define

from inter._client import Client


class Inter:
def __init__(self, client):
self._client = client

@classmethod
def from_credentials(cls, client_id, client_secret, cert_path, key_path):
return cls(client=Client(client_id, client_secret, cert_path, key_path))

def get_balance(self, date=None):
"""
Retorna o saldo disponível da conta em determinado dia.
:param date: data do saldo
:type date: :class:`datetime.date`
:return: saldo disponível
:rtype: :class:`decimal.Decimal`
"""
return Decimal(str(self._client.get_balance(date)['disponivel']))

def get_statement(self, start_date, end_date):
"""
Busca extrato da conta referente as datas recebidas.
:param start_date: data inicial do extrato
:type start_date: :class:`datetime.date`
:param end_date: data final do extrato
:type end_date: :class:`datetime.date`
:return: lista de operações do periodo
:rtype: List[:class:`Operation`]
"""
data = self._client.get_statements(start_date, end_date)['transacoes']
return [Operation.from_data(d) for d in data]


@define
class Operation:
PAYMENT = 'PAGAMENTO'
PIX = 'PIX'

CREDIT = 'C'
DEBIT = 'D'

date: date
"Data da operação"

description: str
"Descrição da Operação"

title: str
"Título da Operação"

type: str
"Tipo da operação. Exemplo: :attr:`PAYMENT`, :attr:`PIX`, etc."

value: Decimal
"Valor da operação. Positivo se for crédito, negativo se for débito"

@classmethod
def from_data(cls, data):
"""
Transforma dados retornados da API em um objeto :class:`Operation`.
:param data: dicionário com dados de uma operação
:type data: `dict`
:return: Operação
:rtype: :class:`Operation`
"""
value = Decimal(str(data['valor']))
value = (value * -1) if data['tipoOperacao'] == cls.DEBIT else value

return cls(
date=datetime.strptime(data['dataEntrada'], '%Y-%m-%d').date(),
description=data['descricao'],
title=data['titulo'],
type=data['tipoTransacao'],
value=value,
)
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@

[project]
name="bancointer"
version = "0.0.3"
version = "0.0.4"
description = "Client to consume Banco Inter APIs"
readme = "README.md"
requires-python = ">=3.7"
Expand All @@ -22,6 +21,7 @@ classifiers = [
'Programming Language :: Python :: 3.10',
]
dependencies = [
"attrs==22.1.0",
"requests==2.28.1",
]

Expand Down
3 changes: 2 additions & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[bumpversion]
current_version = 0.0.3
current_version = 0.0.4
commit = True
tag = True

Expand All @@ -13,3 +13,4 @@ replace = __version__ = '{new_version}'

[flake8]
exclude = docs
max-line-length = 99
8 changes: 8 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@
def statements_data():
return {
'transacoes': [
{
'dataEntrada': '2022-09-11',
'tipoTransacao': 'PIX',
'tipoOperacao': 'C',
'valor': '123.45',
'titulo': 'Pix recebido',
'descricao': 'PIX RECEBIDO - Cp :12345678-EMPRESA TECNOLOGIA LTDA',
},
{
'dataEntrada': '2022-09-10',
'tipoTransacao': 'PAGAMENTO',
Expand Down
132 changes: 132 additions & 0 deletions tests/test_client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
from uuid import uuid4

import pytest
import responses
from responses import matchers

from inter import Client
from inter._client import URL


@pytest.fixture
def client(faker):
client_id, client_secret = faker.pystr(), faker.pystr()
cert_path, key_path = faker.file_path(), faker.file_path()
return Client(client_id, client_secret, cert_path, key_path)


def test_init(faker):
client_id, client_secret = faker.pystr(), faker.pystr()
cert_path, key_path = faker.file_path(), faker.file_path()

client = Client(client_id, client_secret, cert_path, key_path)

assert client.client_id == client_id
assert client.client_secret == client_secret
assert client.cert_path == cert_path
assert client.key_path == key_path


@responses.activate
def test_token(client):
token = str(uuid4())

responses.post(
URL.AUTH,
json={
"access_token": token,
"token_type": "Bearer",
"expires_in": 3600,
"scope": "extrato.read",
},
status=200,
match=[
matchers.urlencoded_params_matcher(
{
'client_id': client.client_id,
'client_secret': client.client_secret,
'scope': 'extrato.read',
'grant_type': 'client_credentials',
}
),
matchers.request_kwargs_matcher({'cert': (client.cert_path, client.key_path)})
],
)

assert client.token == token


def test_cached_token(client):
token = str(uuid4())

client._token = token

assert client.token == token


def test_headers(client):
token = str(uuid4())

client._token = token

assert client.headers == {"Authorization": f"Bearer {client.token}"}


@responses.activate
def test_get_statements(faker, client, statements_data):
client._token = uuid4()
start, end = faker.past_date(), faker.past_date()

responses.get(
URL.STATEMENTS,
json=statements_data,
status=200,
match=[
matchers.query_param_matcher(
{
'dataInicio': start.strftime('%Y-%m-%d'),
'dataFim': end.strftime('%Y-%m-%d'),
}
),
matchers.header_matcher(client.headers),
matchers.request_kwargs_matcher({'cert': (client.cert_path, client.key_path)})
],
)

assert client.get_statements(start, end) == statements_data


@responses.activate
def test_get_balance(faker, client, balance_data):
client._token = uuid4()

responses.get(
URL.BALANCE,
json=balance_data,
status=200,
match=[
matchers.header_matcher(client.headers),
matchers.request_kwargs_matcher({'cert': (client.cert_path, client.key_path)})
],
)

assert client.get_balance() == balance_data


@responses.activate
def test_get_balance_with_date(faker, client, balance_data):
client._token = uuid4()
date = faker.past_date()

responses.get(
URL.BALANCE,
json=balance_data,
status=200,
match=[
matchers.query_param_matcher({'dataSaldo': date.strftime('%Y-%m-%d')}),
matchers.header_matcher(client.headers),
matchers.request_kwargs_matcher({'cert': (client.cert_path, client.key_path)})
],
)

assert client.get_balance(date) == balance_data
Loading

0 comments on commit 40d4e27

Please sign in to comment.