Skip to content

Commit

Permalink
Fix credit card statements & support multiple cards (#209)
Browse files Browse the repository at this point in the history
* fixed credit card statements & support multiple cards

* Add test fo AuthenticatedHome.menu_op

* Add tests for AuthenticatedHomePage.menu_op

* Add Menu2Page

* Add tests for CardDetails page

* Fix tests get_credit_card_invoice

---------

Co-authored-by: Ivan Neto <ivan.cr.neto@gmail.com>
  • Loading branch information
lucasrcezimbra and ivancrneto authored Aug 22, 2023
1 parent b97ca0a commit 78ef8ec
Show file tree
Hide file tree
Showing 9 changed files with 711 additions and 116 deletions.
49 changes: 34 additions & 15 deletions pyitau/main.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import requests
from cached_property import cached_property

from pyitau.pages import (AuthenticatedHomePage, CardDetails, CardsPage,
from pyitau.pages import (AuthenticatedHomePage, CardDetails,
CheckingAccountFullStatement, CheckingAccountMenu,
CheckingAccountStatementsPage, CheckingCardsMenu,
FirstRouterPage, MenuPage, PasswordPage,
SecondRouterPage, ThirdRouterPage)
CheckingAccountStatementsPage, FirstRouterPage,
Menu2Page, MenuPage, PasswordPage, SecondRouterPage,
ThirdRouterPage)

ROUTER_URL = 'https://internetpf5.itau.com.br/router-app/router'

Expand Down Expand Up @@ -37,26 +37,45 @@ def authenticate(self):
self._authenticate8()
self._authenticate9()

def get_credit_card_invoice(self):
def get_credit_card_invoice(self, card_name=None):
"""
Get and return the credit card invoice.
"""
self._session.post(ROUTER_URL, headers={"op": self._home.op, "segmento": "VAREJO"})

response = self._session.post(ROUTER_URL, headers={"op": self._home.menu_op})
# TODO: is it possible to use only Menu2Page and remove MenuPage?
menu = Menu2Page(response.text)

response = self._session.post(ROUTER_URL, headers={
"op": menu.checking_cards_op,
"X-FLOW-ID": self._flow_id,
"X-CLIENT-ID": self._client_id,
"X-Requested-With": "XMLHttpRequest",
})
card_details = CardDetails(response.text)

response = self._session.post(
ROUTER_URL,
headers={'op': self._menu_page.checking_cards_op}
headers={"op": card_details.invoice_op},
data={"secao": "Cartoes", "item": "Home"},
)
cards = response.json()["object"]["data"]

cards_menu = CheckingCardsMenu(response.text)
response = self._session.post(ROUTER_URL, headers={'op': cards_menu.cards_op})
self._session.post(
ROUTER_URL,
headers={"op": card_details.invoice_op},
data={"secao": "Cartoes:MinhaFatura", "item": ""},
)

cards_page = CardsPage(response.text)
response = self._session.post(ROUTER_URL, headers={'op': cards_page.card_details_op},
data={'idCartao': cards_page.first_card_id})
if not card_name:
card_id = cards[0]['id']
else:
card_id = next(c for c in cards if c['nome'] == card_name)['id']

card_details = CardDetails(response.text)
response = self._session.post(ROUTER_URL, headers={'op': card_details.full_invoice_op},
data={'secao': 'Cartoes:MinhaFatura',
'item': ''})
response = self._session.post(
ROUTER_URL, headers={"op": card_details.full_statement_op}, data=card_id
)
return response.json()

def get_statements(self, days=90):
Expand Down
39 changes: 34 additions & 5 deletions pyitau/pages.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,17 @@ class AuthenticatedHomePage(SoupPage):
def op(self):
return self._soup.find('div', class_='logo left').find('a').attrs['data-op']

@property
def menu_op(self):
return re.search(
r"var obterMenu = function\(\) \{"
r'[\n\t\r\s]+var perfil = \$\("#portalTxt"\).val\(\);'
r"[\n\t\r\s]+\$.ajax\(\{"
r'[\n\t\r\s]+url : "([^"]+)"',
self._text,
flags=re.DOTALL,
).group(1)


class MenuPage(TextPage):
@property
Expand All @@ -174,13 +185,15 @@ def checking_account_op(self):
flags=re.DOTALL,
).group(1)


class Menu2Page(TextPage):
@property
def checking_cards_op(self):
return re.search(
r'urlBox : "([^"]+)"[\n\t\r\s,]*seletorContainer : "#boxCartoes",',
r"'cartoes','homeCategoria'(.*?)\"[\n\r\s\t]+data-op=\'([^\']+)\'",
self._text,
flags=re.DOTALL,
).group(1)
).group(2)


class CheckingAccountMenu(TextPage):
Expand Down Expand Up @@ -239,10 +252,26 @@ def filter_statements_by_month_op(self):

class CardDetails(TextPage):
@property
def full_invoice_op(self):
def invoice_op(self):
try:
return re.search(
r'if \(habilitaFaturaCotacaoDolar === "true"\) '
r'{[\n\t\r\s]+urlContingencia = "([^"]+)"',
self._text,
flags=re.DOTALL,
).group(1)
except AttributeError:
return re.search(
r'if \(habilitaDashboardCotacaoDolar === "true"\) '
r'{[\n\t\r\s]+urlContingencia = "([^"]+)"',
self._text,
flags=re.DOTALL,
).group(1)

@property
def full_statement_op(self):
return re.search(
r'if \(habilitaFaturaCotacaoDolar === "true"\) '
r'{[\n\t\r\s]+urlContingencia = "([^"]+)"',
r"data: cartaoSelecionado.id," r'[\n\t\r\s]+url: "([^"]+)"',
self._text,
flags=re.DOTALL,
).group(1)
77 changes: 61 additions & 16 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,22 +55,51 @@ def response_card_details():
@pytest.fixture
def response_authenticated_home():
return """
<div class="logo left">
<a
data-op="PYITAU_OP"
href=""
id="HomeLogo"
onclick="GA.pushHeader('logoItau');"
title="Home"
>
<img
alt="Logo Itaú"
height="50"
src="https://estatico.itau.com.br/.../logo-itau.png"
width="50"
/>
</a>
</div>
<input type="hidden" id="portalTxt" value="varejo"/>
<script id="item" type="text/javascript">
var obterMenu = function() {
var perfil = $("#portalTxt").val();
$.ajax({
url : "PYITAU_MENU_OP",
dataType : "html",
method : "POST",
async: true,
showLoading: false,
headers : {
"ajaxRequest" : true
},
success : function(data) {
$("#menu_p_fisica").replaceWith(data);
},
error : function(erro){
$("#formError").submit();
}
});
};
if(window.addEventListener){
window.addEventListener('load', obterMenu)
} else {
window.attachEvent('onload', obterMenu)
}
</script></li>
</ul>
</nav>
<div class="logo left">
<a onclick="GA.pushHeader('logoItau');" href=""
title="Home"
id="HomeLogo"
data-op="PYITAU_OP">
<img src="https://estatico.itau.com.br/.../logo-itau.png" width="50"
height="50" alt="Logo Ita&uacute;" />
</a>
</div>
"""


Expand Down Expand Up @@ -113,6 +142,22 @@ def response_checking_statements():
"""


@pytest.fixture
def response_menu2():
return """
<li class="titulo " >
<a onclick="GA.pushMegaMenu('cartoes','homeCategoria');...;"
data-op='PYITAU_OP_cartoes'
href="javascript:;"
tabindex="24"
>
cart&otilde;es
</a>
</li>
"""


@pytest.fixture
def response_checking_full_statement():
with open('./tests/responses/checking_account_full_statement.html') as file:
Expand Down
25 changes: 6 additions & 19 deletions tests/pages/test_authenticated_home.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,8 @@


@pytest.fixture
def response():
return """
<div class="logo left">
<a
data-op="PYITAU_OP"
href=""
id="HomeLogo"
onclick="GA.pushHeader('logoItau');"
title="Home"
>
<img
alt="Logo Itaú"
height="50"
src="https://estatico.itau.com.br/.../logo-itau.png"
width="50"
/>
</a>
</div>
"""
def response(response_authenticated_home):
return response_authenticated_home


@pytest.fixture
Expand All @@ -36,5 +19,9 @@ def test_init(response):
assert page._soup == BeautifulSoup(response, features='html.parser')


def test_menu_op(page):
assert page.menu_op == 'PYITAU_MENU_OP'


def test_op(page):
assert page.op == 'PYITAU_OP'
18 changes: 14 additions & 4 deletions tests/pages/test_card_details.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
import pytest

from pyitau.pages import CardDetails


def test_init(response_card_details: str):
@pytest.fixture
def page(response_card_details):
return CardDetails(response_card_details)


def test_init(response_card_details):
card_details = CardDetails(response_card_details)
assert card_details._text == response_card_details


def test_op(response_card_details: str):
card_details = CardDetails(response_card_details)
assert card_details.full_invoice_op == 'PYITAU_URL_CONTIGENCIA_DOLAR_OP'
def test_invoice_op(page):
assert page.invoice_op == "PYITAU_invoice_op"


def test_full_statement_op(page):
assert page.full_statement_op == "PYITAU_full_statement_op"
4 changes: 0 additions & 4 deletions tests/pages/test_menu.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,3 @@ def test_init(response_menu):

def test_op(page):
assert page.checking_account_op == 'PYITAU_OP_ContaCorrente'


def test_checking_cards_op(page: MenuPage):
assert page.checking_cards_op == 'PYITAU_OP_Cartoes'
22 changes: 22 additions & 0 deletions tests/pages/test_menu2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import pytest

from pyitau.pages import Menu2Page


@pytest.fixture
def response(response_menu2):
return response_menu2


@pytest.fixture
def page(response):
return Menu2Page(response)


def test_init(response):
page = Menu2Page(response)
assert page._text == response


def test_checking_cards_op(page):
assert page.checking_cards_op == 'PYITAU_OP_cartoes'
Loading

0 comments on commit 78ef8ec

Please sign in to comment.