citelis: Support transaction history

This commit is contained in:
Laurent Bachelier 2013-07-29 19:08:06 +02:00 committed by Romain Bignon
commit 834c30b1e8
3 changed files with 72 additions and 5 deletions

View file

@ -20,7 +20,7 @@
from weboob.tools.backend import BaseBackend, BackendConfig from weboob.tools.backend import BaseBackend, BackendConfig
from weboob.tools.value import ValueBackendPassword from weboob.tools.value import ValueBackendPassword
from weboob.capabilities.bank import ICapBank from weboob.capabilities.bank import ICapBank, AccountNotFound
from .browser import CitelisBrowser from .browser import CitelisBrowser
@ -50,3 +50,12 @@ class CitelisBackend(BaseBackend, ICapBank):
def iter_accounts(self): def iter_accounts(self):
return self.browser.get_accounts_list() 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)

View file

@ -21,7 +21,7 @@
from weboob.capabilities.bank import Account from weboob.capabilities.bank import Account
from weboob.tools.browser import BaseBrowser, BrowserIncorrectPassword from weboob.tools.browser import BaseBrowser, BrowserIncorrectPassword
from .pages import LoginPage, SummaryPage, UselessPage from .pages import LoginPage, SummaryPage, UselessPage, TransactionSearchPage, TransactionsPage, TransactionsCsvPage
__all__ = ['CitelisBrowser'] __all__ = ['CitelisBrowser']
@ -37,6 +37,9 @@ class CitelisBrowser(BaseBrowser):
'%s://%s/userManager\.do\?reqCode=prepareLogin.*' % (PROTOCOL, DOMAIN): LoginPage, '%s://%s/userManager\.do\?reqCode=prepareLogin.*' % (PROTOCOL, DOMAIN): LoginPage,
'%s://%s/summarySearch\.do\?reqCode=search.*' % (PROTOCOL, DOMAIN): SummaryPage, '%s://%s/summarySearch\.do\?reqCode=search.*' % (PROTOCOL, DOMAIN): SummaryPage,
'%s://%s/userManager\.do\?reqCode=goToHomePage.+' % (PROTOCOL, DOMAIN): UselessPage, '%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): def __init__(self, merchant_id, *args, **kwargs):
@ -61,3 +64,13 @@ class CitelisBrowser(BaseBrowser):
account.balance = self.page.get_balance() account.balance = self.page.get_balance()
account.label = u'Synthèse financière' account.label = u'Synthèse financière'
return [account] 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

View file

@ -19,15 +19,13 @@
from decimal import Decimal from decimal import Decimal
import datetime
import re import re
from weboob.tools.browser import BasePage from weboob.tools.browser import BasePage
from weboob.tools.capabilities.bank.transactions import FrenchTransaction from weboob.tools.capabilities.bank.transactions import FrenchTransaction
__all__ = ['LoginPage', 'SummaryPage', 'UselessPage']
class Transaction(FrenchTransaction): class Transaction(FrenchTransaction):
@classmethod @classmethod
def clean_amount(cls, text): def clean_amount(cls, text):
@ -70,3 +68,50 @@ class SummaryPage(BasePage):
class UselessPage(BasePage): class UselessPage(BasePage):
pass 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