support full list of accounts (closes #1360)

This commit is contained in:
Romain Bignon 2014-12-26 11:40:54 +01:00
commit c18ba9072c
2 changed files with 83 additions and 21 deletions

View file

@ -22,7 +22,7 @@ import urllib
from weboob.deprecated.browser import Browser, BrowserIncorrectPassword, BrokenPageError
from .pages import LoginPage, IndexPage, AccountsPage, CardsPage, TransactionsPage, \
from .pages import LoginPage, IndexPage, AccountsPage, AccountsFullPage, CardsPage, TransactionsPage, \
UnavailablePage, RedirectPage, HomePage, Login2Page
@ -37,7 +37,8 @@ class BanquePopulaire(Browser):
'https://[^/]+/cyber/internet/StartTask.do\?taskInfoOID=mesComptes.*': AccountsPage,
'https://[^/]+/cyber/internet/StartTask.do\?taskInfoOID=maSyntheseGratuite.*': AccountsPage,
'https://[^/]+/cyber/internet/StartTask.do\?taskInfoOID=accueilSynthese.*': AccountsPage,
'https://[^/]+/cyber/internet/ContinueTask.do\?.*dialogActionPerformed=EQUIPEMENT_COMPLET.*': AccountsPage,
'https://[^/]+/cyber/internet/ContinueTask.do\?.*dialogActionPerformed=EQUIPEMENT_COMPLET.*': AccountsFullPage,
'https://[^/]+/cyber/internet/ContinueTask.do\?.*dialogActionPerformed=VUE_COMPLETE.*': AccountsPage,
'https://[^/]+/cyber/internet/ContinueTask.do\?.*dialogActionPerformed=ENCOURS_COMPTE.*': CardsPage,
'https://[^/]+/cyber/internet/ContinueTask.do\?.*dialogActionPerformed=SELECTION_ENCOURS_CARTE.*': TransactionsPage,
'https://[^/]+/cyber/internet/ContinueTask.do\?.*dialogActionPerformed=SOLDE.*': TransactionsPage,
@ -109,14 +110,22 @@ class BanquePopulaire(Browser):
for a in self.page.iter_accounts(next_pages):
yield a
for next_page in next_pages:
if not self.is_on_page(AccountsPage):
while len(next_pages) > 0:
next_page = next_pages.pop()
if not self.is_on_page(AccountsFullPage):
self.go_on_accounts_list()
# If there is an action needed to go to the "next page", do it.
if 'prevAction' in next_page:
params = self.page.get_params()
params['dialogActionPerformed'] = next_page.pop('prevAction')
params['token'] = self.page.build_token(self.page.get_token())
self.location('/cyber/internet/ContinueTask.do', urllib.urlencode(params))
next_page['token'] = self.page.build_token(self.page.get_token())
self.location('/cyber/internet/ContinueTask.do', urllib.urlencode(next_page))
for a in self.page.iter_accounts():
for a in self.page.iter_accounts(next_pages):
yield a
def get_account(self, id):

View file

@ -86,6 +86,24 @@ class BasePage(_BasePage):
token += token[i]
return token
def get_params(self):
params = {}
for field in self.document.xpath('//input'):
params[field.attrib['name']] = field.attrib.get('value', '')
return params
def get_button_actions(self):
actions = {}
for script in self.document.xpath('//script'):
if script.text is None:
continue
for id, action, strategy in re.findall(r'''attEvt\(window,"(?P<id>[^"]+)","click","sab\('(?P<action>[^']+)','(?P<strategy>[^']+)'\);"''', script.text, re.MULTILINE):
actions[id] = {'dialogActionPerformed': action,
'validationStrategy': strategy,
}
return actions
class RedirectPage(BasePage):
"""
@ -276,14 +294,18 @@ class HomePage(BasePage):
class AccountsPage(BasePage):
ACCOUNT_TYPES = {u'Mes comptes d\'épargne': Account.TYPE_SAVINGS,
u'Mon épargne': Account.TYPE_SAVINGS,
u'Placements': Account.TYPE_SAVINGS,
u'Mes comptes': Account.TYPE_CHECKING,
u'Comptes en euros': Account.TYPE_CHECKING,
u'Mes emprunts': Account.TYPE_LOAN,
u'Financements': Account.TYPE_LOAN,
u'Mes services': None, # ignore this kind of accounts (no bank ones)
ACCOUNT_TYPES = {u'Mes comptes d\'épargne': Account.TYPE_SAVINGS,
u'Mon épargne': Account.TYPE_SAVINGS,
u'Placements': Account.TYPE_SAVINGS,
u'Liste complète de mon épargne': Account.TYPE_SAVINGS,
u'Mes comptes': Account.TYPE_CHECKING,
u'Comptes en euros': Account.TYPE_CHECKING,
u'Liste complète de mes comptes': Account.TYPE_CHECKING,
u'Mes emprunts': Account.TYPE_LOAN,
u'Financements': Account.TYPE_LOAN,
u'Mes services': None, # ignore this kind of accounts (no bank ones)
u'Équipements': None, # ignore this kind of accounts (no bank ones)
u'Synthèse': None, # ignore this title
}
def is_error(self):
@ -307,12 +329,11 @@ class AccountsPage(BasePage):
def iter_accounts(self, next_pages):
account_type = Account.TYPE_UNKNOWN
params = {}
for field in self.document.xpath('//input'):
params[field.attrib['name']] = field.attrib.get('value', '')
params = self.get_params()
actions = self.get_button_actions()
for div in self.document.getroot().cssselect('div.btit'):
if div.text is None:
if div.text in (None, u'Synthèse'):
continue
account_type = self.ACCOUNT_TYPES.get(div.text.strip(), Account.TYPE_UNKNOWN)
@ -320,6 +341,15 @@ class AccountsPage(BasePage):
# ignore services accounts
continue
# Go to the full list of this kind of account, if any.
btn = div.getparent().xpath('.//button/span[text()="Suite"]')
if len(btn) > 0:
btn = btn[0].getparent()
_params = params.copy()
_params.update(actions[btn.attrib['id']])
next_pages.append(_params)
continue
currency = None
for th in div.getnext().xpath('.//thead//th'):
m = re.match('.*\((\w+)\)$', th.text)
@ -361,9 +391,24 @@ class AccountsPage(BasePage):
if len(tds) >= 5 and len(tds[self.COL_COMING].xpath('.//a')) > 0:
_params = account._params.copy()
_params['dialogActionPerformed'] = 'ENCOURS_COMPTE'
# If there is an action needed before going to the cards page, save it.
m = re.search('dialogActionPerformed=([\w_]+)', self.url)
if m:
_params['prevAction'] = m.group(1)
next_pages.append(_params)
yield account
# Needed to preserve navigation.
btn = self.document.xpath('.//button/span[text()="Retour"]')
if len(btn) > 0:
btn = btn[0].getparent()
_params = params.copy()
_params.update(actions[btn.attrib['id']])
self.browser.openurl('/cyber/internet/ContinueTask.do', urllib.urlencode(_params))
class AccountsFullPage(AccountsPage):
pass
class CardsPage(BasePage):
COL_ID = 0
@ -372,10 +417,8 @@ class CardsPage(BasePage):
COL_DATE = 3
COL_AMOUNT = 4
def iter_accounts(self):
params = {}
for field in self.document.xpath('//input'):
params[field.attrib['name']] = field.attrib.get('value', '')
def iter_accounts(self, next_pages):
params = self.get_params()
account = None
for tr in self.document.xpath('//table[@id="TabCtes"]/tbody/tr'):
@ -387,6 +430,7 @@ class CardsPage(BasePage):
yield account
account = Account()
account.id = id.replace(' ', '')
account.type = Account.TYPE_CARD
account.balance = account.coming = Decimal('0')
account._next_debit = datetime.date.today()
account._prev_debit = datetime.date(2000,1,1)
@ -426,6 +470,15 @@ class CardsPage(BasePage):
if account is not None:
yield account
# Needed to preserve navigation.
btn = self.document.xpath('.//button/span[text()="Retour"]')
if len(btn) > 0:
btn = btn[0].getparent()
actions = self.get_button_actions()
_params = params.copy()
_params.update(actions[btn.attrib['id']])
self.browser.openurl('/cyber/internet/ContinueTask.do', urllib.urlencode(_params))
class Transaction(FrenchTransaction):
PATTERNS = [(re.compile('^RET DAB (?P<text>.*?) RETRAIT (DU|LE) (?P<dd>\d{2})(?P<mm>\d{2})(?P<yy>\d+).*'),