From 07038a9989bef6fa3934c56ad8fe29b83bac2696 Mon Sep 17 00:00:00 2001 From: Romain Bignon Date: Tue, 15 Jan 2013 15:39:56 +0100 Subject: [PATCH] support deferred debit --- modules/bp/backend.py | 21 +++++++------- modules/bp/browser.py | 45 +++++++++++++++++++++++++++--- modules/bp/pages/__init__.py | 5 ++-- modules/bp/pages/accounthistory.py | 44 +++++++++++++++++++++++++++-- modules/bp/pages/accountlist.py | 24 +++++++++++----- 5 files changed, 114 insertions(+), 25 deletions(-) diff --git a/modules/bp/backend.py b/modules/bp/backend.py index e476edc7..d98153eb 100644 --- a/modules/bp/backend.py +++ b/modules/bp/backend.py @@ -18,7 +18,7 @@ # along with weboob. If not, see . -from weboob.capabilities.bank import ICapBank, AccountNotFound +from weboob.capabilities.bank import ICapBank from weboob.tools.backend import BaseBackend, BackendConfig from weboob.tools.value import ValueBackendPassword @@ -43,19 +43,20 @@ class BPBackend(BaseBackend, ICapBank): return self.create_browser(self.config['login'].get(), self.config['password'].get()) def iter_accounts(self): - for account in self.browser.get_accounts_list(): - yield account + return self.browser.get_accounts_list() def get_account(self, _id): - account = self.browser.get_account(_id) - if account: - return account - else: - raise AccountNotFound() + return self.browser.get_account(_id) def iter_history(self, account): - for history in self.browser.get_history(account): - yield history + for tr in self.browser.get_history(account): + if not tr._coming: + yield tr + + def iter_coming(self, account): + for tr in self.browser.get_coming(account): + if tr._coming: + yield tr def transfer(self, id_from, id_to, amount, reason=None): from_account = self.get_account(id_from) diff --git a/modules/bp/browser.py b/modules/bp/browser.py index d6cb9c47..636d7e34 100644 --- a/modules/bp/browser.py +++ b/modules/bp/browser.py @@ -24,7 +24,7 @@ from datetime import datetime from weboob.tools.browser import BaseBrowser, BrowserIncorrectPassword, BrowserBanned from .pages import LoginPage, Initident, CheckPassword, repositionnerCheminCourant, BadLoginPage, AccountDesactivate, \ - AccountList, AccountHistory, UnavailablePage, \ + AccountList, AccountHistory, CardsList, UnavailablePage, \ TransferChooseAccounts, CompleteTransfer, TransferConfirm, TransferSummary from weboob.capabilities.bank import Transfer @@ -48,6 +48,8 @@ class BPBrowser(BaseBrowser): r'.*CCP/releves_ccp/releveCPP-releve_ccp\.ea' : AccountHistory, r'.*CNE/releveCNE/releveCNE-releve_cne\.ea' : AccountHistory, + r'.*CB/releveCB/preparerRecherche-mouvementsCarteDD.ea.*' : AccountHistory, + r'.*CB/releveCB/init-mouvementsCarteDD.ea.*' : CardsList, r'.*/virementSafran_aiguillage/init-saisieComptes\.ea' : TransferChooseAccounts, r'.*/virementSafran_aiguillage/formAiguillage-saisieComptes\.ea' : CompleteTransfer, @@ -98,9 +100,44 @@ class BPBrowser(BaseBrowser): args['typeRecherche'] = 10 self.location(self.buildurl(v.path, **args)) - if not self.is_on_page(AccountHistory): - return iter([]) - return self.page.get_history() + + if self.is_on_page(AccountHistory): + for tr in self.page.get_history(): + yield tr + + for tr in self.get_coming(account): + yield tr + + def get_coming(self, account): + for card in account._card_links: + self.location(card) + + if self.is_on_page(CardsList): + for link in self.page.get_cards(): + self.location(link) + + for tr in self._iter_card_tr(): + yield tr + else: + for tr in self._iter_card_tr(): + yield tr + + def _iter_card_tr(self): + """ + Iter all pages until there are no transactions. + """ + ops = self.page.get_history(deferred=True) + + while len(ops) > 0: + for tr in ops: + yield tr + + link = self.page.get_next_link() + if link is None: + return + + self.location(link) + ops = self.page.get_history(deferred=True) def make_transfer(self, from_account, to_account, amount): self.location('https://voscomptesenligne.labanquepostale.fr/voscomptes/canalXHTML/virement/virementSafran_aiguillage/init-saisieComptes.ea') diff --git a/modules/bp/pages/__init__.py b/modules/bp/pages/__init__.py index 60397122..c6d74648 100644 --- a/modules/bp/pages/__init__.py +++ b/modules/bp/pages/__init__.py @@ -20,9 +20,10 @@ from .login import LoginPage, Initident, CheckPassword,repositionnerCheminCourant, BadLoginPage, AccountDesactivate, UnavailablePage from .accountlist import AccountList -from .accounthistory import AccountHistory +from .accounthistory import AccountHistory, CardsList from .transfer import TransferChooseAccounts, CompleteTransfer, TransferConfirm, TransferSummary __all__ = ['LoginPage','Initident', 'CheckPassword', 'repositionnerCheminCourant', "AccountList", 'AccountHistory', 'BadLoginPage', - 'AccountDesactivate', 'TransferChooseAccounts', 'CompleteTransfer', 'TransferConfirm', 'TransferSummary', 'UnavailablePage'] + 'AccountDesactivate', 'TransferChooseAccounts', 'CompleteTransfer', 'TransferConfirm', 'TransferSummary', 'UnavailablePage', + 'CardsList'] diff --git a/modules/bp/pages/accounthistory.py b/modules/bp/pages/accounthistory.py index ce5f1471..2a04fa6e 100644 --- a/modules/bp/pages/accounthistory.py +++ b/modules/bp/pages/accounthistory.py @@ -18,13 +18,14 @@ # along with weboob. If not, see . +import datetime import re from weboob.tools.capabilities.bank.transactions import FrenchTransaction from weboob.tools.browser import BasePage -__all__ = ['AccountHistory'] +__all__ = ['AccountHistory', 'CardsList'] class Transaction(FrenchTransaction): @@ -47,17 +48,39 @@ class Transaction(FrenchTransaction): ] class AccountHistory(BasePage): - def get_history(self): + def get_next_link(self): + for a in self.document.xpath('//a[@class="btn_crt"]'): + txt = u''.join([txt.strip() for txt in a.itertext()]) + if u'mois précédent' in txt: + return a.attrib['href'] + + def get_history(self, deferred=False): + """ + deffered is True when we are on a card page. + """ mvt_table = self.document.xpath("//table[@id='mouvements']", smart_strings=False)[0] mvt_ligne = mvt_table.xpath("./tbody/tr") operations = [] + if deferred: + # look for the debit date, and if it is already debited + txt = u''.join([txt.strip() for txt in self.document.xpath('//div[@class="infosynthese"]')[0].itertext()]) + m = re.search('(\d+)/(\d+)/(\d+)', txt) + if m: + debit_date = datetime.date(*map(int, reversed(m.groups()))) + coming = 'En cours' in txt + else: + coming = False + for mvt in mvt_ligne: op = Transaction(len(operations)) op.parse(date=mvt.xpath("./td/span")[0].text.strip(), raw=unicode(self.parser.tocleanstring(mvt.xpath('./td/span')[1]).strip())) + if op.label.startswith('DEBIT CARTE BANCAIRE DIFFERE'): + continue + r = re.compile(r'\d+') tmp = mvt.xpath("./td/span/strong") @@ -70,5 +93,22 @@ class AccountHistory(BasePage): op.set_amount(amount) + if deferred: + op.rdate = op.date + op.date = debit_date + # on card page, amounts are without sign + if op.amount > 0: + op.amount = - op.amount + + op._coming = coming + operations.append(op) return operations + +class CardsList(BasePage): + def get_cards(self): + cards = [] + for tr in self.document.xpath('//table[@class="dataNum"]/tbody/tr'): + cards.append(tr.xpath('.//a')[0].attrib['href']) + + return cards diff --git a/modules/bp/pages/accountlist.py b/modules/bp/pages/accountlist.py index 6f68d04d..aa9d7a3e 100644 --- a/modules/bp/pages/accountlist.py +++ b/modules/bp/pages/accountlist.py @@ -24,6 +24,7 @@ from weboob.capabilities.bank import Account, AccountNotFound from weboob.tools.browser import BasePage from weboob.tools.misc import to_unicode from weboob.tools.capabilities.bank.transactions import FrenchTransaction +from weboob.tools.ordereddict import OrderedDict __all__ = ['AccountList'] @@ -31,7 +32,7 @@ __all__ = ['AccountList'] class AccountList(BasePage): def on_loaded(self): - self.account_list = [] + self.accounts = OrderedDict() self.parse_table('comptes') self.parse_table('comptesEpargne') self.parse_table('comptesTitres') @@ -39,7 +40,7 @@ class AccountList(BasePage): self.parse_table('comptesRetraireEuros') def get_accounts_list(self): - return self.account_list + return self.accounts.itervalues() def parse_table(self, what): tables = self.document.xpath("//table[@id='%s']" % what, smart_strings=False) @@ -66,10 +67,19 @@ class AccountList(BasePage): account.id = tmp_id account.currency = account.get_currency(tmp_balance) account.balance = Decimal(FrenchTransaction.clean_amount(tmp_balance)) - self.account_list.append(account) + + if account.id in self.accounts: + a = self.accounts[account.id] + a._card_links.append(account._link_id) + if not a.coming: + a.coming = Decimal('0.0') + a.coming += account.balance + else: + account._card_links = [] + self.accounts[account.id] = account def get_account(self, id): - for account in self.account_list: - if account.id == id: - return account - raise AccountNotFound('Unable to find account: %s' % id) + try: + return self.accounts[id] + except KeyError: + raise AccountNotFound('Unable to find account: %s' % id)