diff --git a/modules/citelis/backend.py b/modules/citelis/backend.py index 13aa8500..f84d503d 100644 --- a/modules/citelis/backend.py +++ b/modules/citelis/backend.py @@ -20,7 +20,7 @@ from weboob.tools.backend import BaseBackend, BackendConfig from weboob.tools.value import ValueBackendPassword -from weboob.capabilities.bank import ICapBank +from weboob.capabilities.bank import ICapBank, AccountNotFound from .browser import CitelisBrowser @@ -50,3 +50,12 @@ class CitelisBackend(BaseBackend, ICapBank): def iter_accounts(self): return self.browser.get_accounts_list() + + def get_account(self, _id): + for account in self.iter_accounts(): + if account.id == _id: + return account + raise AccountNotFound() + + def iter_history(self, account): + return self.browser.iter_history(account) diff --git a/modules/citelis/browser.py b/modules/citelis/browser.py index 29a059ba..1f74d7f5 100644 --- a/modules/citelis/browser.py +++ b/modules/citelis/browser.py @@ -21,7 +21,7 @@ from weboob.capabilities.bank import Account from weboob.tools.browser import BaseBrowser, BrowserIncorrectPassword -from .pages import LoginPage, SummaryPage, UselessPage +from .pages import LoginPage, SummaryPage, UselessPage, TransactionSearchPage, TransactionsPage, TransactionsCsvPage __all__ = ['CitelisBrowser'] @@ -37,6 +37,9 @@ class CitelisBrowser(BaseBrowser): '%s://%s/userManager\.do\?reqCode=prepareLogin.*' % (PROTOCOL, DOMAIN): LoginPage, '%s://%s/summarySearch\.do\?reqCode=search.*' % (PROTOCOL, DOMAIN): SummaryPage, '%s://%s/userManager\.do\?reqCode=goToHomePage.+' % (PROTOCOL, DOMAIN): UselessPage, + '%s://%s/menu\.do\?reqCode=prepareSearchTransaction.+' % (PROTOCOL, DOMAIN): TransactionSearchPage, + '%s://%s/transactionSearch\.do\?reqCode=search.+' % (PROTOCOL, DOMAIN): TransactionsPage, + '%s://%s/documents/transaction/l_TransactionSearchWebBooster\.jsp.+' % (PROTOCOL, DOMAIN): (TransactionsCsvPage, 'csv') } def __init__(self, merchant_id, *args, **kwargs): @@ -61,3 +64,13 @@ class CitelisBrowser(BaseBrowser): account.balance = self.page.get_balance() account.label = u'Synthèse financière' return [account] + + def iter_history(self, account): + assert account.id == '1' + if not self.is_on_page(TransactionSearchPage): + self.location('%s://%s/menu.do?reqCode=prepareSearchTransaction&init=true&screen=new' + % (self.PROTOCOL, self.DOMAIN)) + self.page.search() + self.location(self.page.get_csv_url()) + for transaction in self.page.iter_transactions(): + yield transaction diff --git a/modules/citelis/pages.py b/modules/citelis/pages.py index bcd172d3..f01de09e 100644 --- a/modules/citelis/pages.py +++ b/modules/citelis/pages.py @@ -19,15 +19,13 @@ from decimal import Decimal +import datetime import re from weboob.tools.browser import BasePage from weboob.tools.capabilities.bank.transactions import FrenchTransaction -__all__ = ['LoginPage', 'SummaryPage', 'UselessPage'] - - class Transaction(FrenchTransaction): @classmethod def clean_amount(cls, text): @@ -70,3 +68,50 @@ class SummaryPage(BasePage): class UselessPage(BasePage): pass + + +class TransactionSearchPage(BasePage): + def search(self, accepted=True, refused=False): + self.browser.select_form(name='transactionSearchForm') + self.browser['selectedDateCriteria'] = ['thisweek'] # TODO ask for more + self.browser['transactionAccepted'] = ['0'] if accepted else [] + self.browser['transactionRefused'] = ['0'] if refused else [] + + # simulate the javascript + nonce = self.parser.select(self.document.getroot(), '#menu li.global a')[0] \ + .attrib['href'].partition('CSRF_NONCE=')[2] + self.browser.form.action = '%s://%s/transactionSearch.do?reqCode=%s&org.apache.catalina.filters.CSRF_NONCE=%s&screen=new' % (self.browser.PROTOCOL, self.browser.DOMAIN, 'search', nonce) + self.browser.submit() + + +class TransactionsPage(BasePage): + def get_csv_url(self): + for a in self.parser.select(self.document.getroot(), '.exportlinks a'): + if len(self.parser.select(a, 'span.csv')): + return a.attrib['href'] + + +class TransactionsCsvPage(BasePage): + def guess_format(self, amount): + if re.search(r'\d\.\d\d$', amount): + date_format = "%m/%d/%Y" + else: + date_format = "%d/%m/%Y" + time_format = "%H:%M:%S" + return date_format + ' ' + time_format + + def iter_transactions(self): + ID = 0 + DATE = 2 + AMOUNT = 4 + CARD = 7 + NUMBER = 8 + for row in self.document.rows: + t = Transaction(row[ID]) + date = row[DATE] + amount = row[AMOUNT] + datetime_format = self.guess_format(amount) + t.set_amount(amount) + t.parse(datetime.datetime.strptime(date, datetime_format), + row[CARD] + ' ' + row[NUMBER]) + yield t