From f1d3f03a921b32ed3d76073ef363ba8a0c2e47e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?No=C3=A9=20Rubinstein?= Date: Fri, 26 Jul 2013 20:54:24 +0200 Subject: [PATCH] cragr: add support for credit cards --- modules/cragr/web/browser.py | 32 +++++++++---- modules/cragr/web/pages.py | 92 ++++++++++++++++++++++++++++++++++++ 2 files changed, 116 insertions(+), 8 deletions(-) diff --git a/modules/cragr/web/browser.py b/modules/cragr/web/browser.py index 26ca333e..407b9c0c 100644 --- a/modules/cragr/web/browser.py +++ b/modules/cragr/web/browser.py @@ -24,7 +24,8 @@ import re from weboob.tools.browser import BaseBrowser, BrowserIncorrectPassword from weboob.tools.date import LinearDateGuesser -from .pages import HomePage, LoginPage, LoginErrorPage, AccountsPage, SavingsPage, TransactionsPage, UselessPage +from .pages import HomePage, LoginPage, LoginErrorPage, AccountsPage, \ + SavingsPage, TransactionsPage, UselessPage, CardsPage __all__ = ['Cragr'] @@ -43,6 +44,8 @@ class Cragr(BaseBrowser): 'https?://[^/]+/stb/collecteNI\?.*sessionAPP=Releves.*': TransactionsPage, 'https?://[^/]+/stb/.*/erreur/.*': LoginErrorPage, 'https?://[^/]+/stb/entreeBam\?.*act=Messagesprioritaires': UselessPage, + 'https?://[^/]+/stb/collecteNI\?.*fwkaction=Cartes.*': CardsPage, + 'https?://[^/]+/stb/collecteNI\?.*fwkaction=Detail.*sessionAPP=Cartes.*': CardsPage, } class WebsiteNotSupported(Exception): @@ -127,6 +130,14 @@ class Cragr(BaseBrowser): if not self.is_on_page(AccountsPage): self.location(self.accounts_url) accounts_list.extend(self.page.get_list()) + + # credit cards + cards_page = self.page.cards_page() + if cards_page: + self.location(cards_page) + assert self.is_on_page(CardsPage) + accounts_list.extend(self.page.get_list()) + # savings accounts self.location(self.savings_url) if self.is_on_page(SavingsPage): @@ -150,15 +161,20 @@ class Cragr(BaseBrowser): if account._link is None: return - self.location(account._link) - url = account._link date_guesser = LinearDateGuesser() + self.location(account._link) - while url: - self.location(url) - assert self.is_on_page(TransactionsPage) - + if self.is_on_page(CardsPage): for tr in self.page.get_history(date_guesser): yield tr + else: + url = account._link - url = self.page.get_next_url() + while url: + self.location(url) + assert self.is_on_page(TransactionsPage) + + for tr in self.page.get_history(date_guesser): + yield tr + + url = self.page.get_next_url() diff --git a/modules/cragr/web/pages.py b/modules/cragr/web/pages.py index 6f3d7a14..c5492027 100644 --- a/modules/cragr/web/pages.py +++ b/modules/cragr/web/pages.py @@ -20,6 +20,7 @@ import re from decimal import Decimal +from weboob.tools.date import parse_french_date from weboob.capabilities.bank import Account from weboob.tools.browser import BasePage from weboob.tools.capabilities.bank.transactions import FrenchTransaction as Transaction @@ -101,6 +102,97 @@ class _AccountsPage(BasePage): yield account + def cards_page(self): + try: + return self.document.xpath('//table[@class="ca-table"]' + + '/tr[@class="ligne-connexe"]' + + '//a/@href')[0] + except IndexError: + pass + + +class CardsPage(BasePage): + + def get_list(self): + TABLE_XPATH = '//table[caption[@class="caption tdb-cartes-caption"]]' + + cards_tables = self.document.xpath(TABLE_XPATH) + + if cards_tables: + # There are several cards + xpaths = { + '_id': './caption/span[@class="tdb-cartes-num"]', + 'label1': './caption/span[@class="tdb-cartes-carte l30"]', + 'label2': './caption/span[@class="tdb-cartes-prop"]', + 'balance': './/tr[last()]/td[@class="cel-num"]', + 'currency': '//table/caption//span/text()[starts-with(.,"Montants en ")]', + 'link': './/tr//a/@href', + } + else: + xpaths = { + '_id': './/tr/td[@class="cel-texte"]', + 'label1': './/tr[@class="ligne-impaire ligne-bleu"]/th', + 'label2': './caption/span[@class="tdb-cartes-prop"]/b', + 'balance': './/tr[last()-1]/td[@class="cel-num"]', + 'currency': '//table/caption//span/text()[starts-with(.,"Montants en ")]', + } + TABLE_XPATH = '(//table[@class="ca-table"])[1]' + cards_tables = self.document.xpath(TABLE_XPATH) + + for table in cards_tables: + get = lambda name: self.parser.tocleanstring(table.xpath(xpaths[name])[0]) + + account = Account() + account.id = ''.join(get('_id').split()[1:]) + account.label = '%s - %s' % (get('label1'), + re.sub('\s*-\s*$', '', get('label2'))) + account.balance = Decimal(Transaction.clean_amount(get('balance'))) + account.currency = account.get_currency(self.document + .xpath(xpaths['currency'])[0].replace("Montants en ", "")) + if 'link' in xpaths: + account._link = table.xpath(xpaths['link'])[-1] + else: + account._link = self.url + + yield account + + + def get_history(self, date_guesser): + seen = set() + lines = self.document.xpath('(//table[@class="ca-table"])[2]/tr') + for line in lines[1:]: # first line is balance + is_balance = line.xpath('./td/@class="cel-texte cel-neg"') + + [date, label, _, amount] = [self.parser.tocleanstring(td) + for td in line.xpath('./td')] + + clean_amount = Decimal(Transaction.clean_amount(amount)) + + t = Transaction(0) + + if is_balance: + date_str = label.replace( u"Opérations débitées le ", "") \ + .replace(" :","") + t.date = parse_french_date(date_str) + t.label = u"Débit" + t.amount = -clean_amount + else: + day, month = map(int, date.split('/', 1)) + t.date = date_guesser.guess_date(day, month) + t.label = t.raw = label + t.amount = clean_amount + + t.type = t.TYPE_CARD + t.rdate = t.date + try: + t.id = t.unique_id(seen) + except UnicodeEncodeError: + print t + print t.label + raise + + yield t + class AccountsPage(_AccountsPage): pass