From 85c9554733e740e9ae603b63e9bdaae45d80d388 Mon Sep 17 00:00:00 2001 From: Romain Bignon Date: Wed, 10 Oct 2012 14:44:34 +0200 Subject: [PATCH] support deferred debit cards --- modules/societegenerale/backend.py | 13 ++- modules/societegenerale/browser.py | 21 ++++- .../societegenerale/pages/accounts_list.py | 88 ++++++++++++------- 3 files changed, 81 insertions(+), 41 deletions(-) diff --git a/modules/societegenerale/backend.py b/modules/societegenerale/backend.py index 9b913e0b..cb14556e 100644 --- a/modules/societegenerale/backend.py +++ b/modules/societegenerale/backend.py @@ -60,15 +60,12 @@ class SocieteGeneraleBackend(BaseBackend, ICapBank): def iter_history(self, account): with self.browser: - for tr in self.browser.iter_history(account._link_id): + for tr in self.browser.iter_history(account): if not tr._coming: yield tr def iter_coming(self, account): - return iter([]) - - # XXX do not print coming operations, as their labels are really useless. - #with self.browser: - # for tr in self.browser.iter_history(account._link_id): - # if tr._coming: - # yield tr + with self.browser: + for tr in self.browser.iter_history(account): + if tr._coming: + yield tr diff --git a/modules/societegenerale/browser.py b/modules/societegenerale/browser.py index cd53ed12..977af152 100644 --- a/modules/societegenerale/browser.py +++ b/modules/societegenerale/browser.py @@ -99,12 +99,27 @@ class SocieteGenerale(BaseBrowser): return None - def iter_history(self, url): - self.location(url) + def iter_history(self, account): + self.location(account._link_id) if not self.is_on_page(AccountHistory): # TODO: support other kind of accounts self.logger.warning('This account is not supported') raise NotImplementedError('This account is not supported') - return self.page.iter_transactions() + transactions = list(self.page.iter_transactions(coming=False)) + + for card_link in account._card_links: + self.location(card_link) + + transactions += list(self.page.iter_transactions(coming=True)) + + def key(tr): + # Can't compare datetime and date, so cast them. + try: + return tr.rdate.date() + except AttributeError: + return tr.rdate + + transactions.sort(key=key, reverse=True) + return iter(transactions) diff --git a/modules/societegenerale/pages/accounts_list.py b/modules/societegenerale/pages/accounts_list.py index 833638be..87a35b15 100644 --- a/modules/societegenerale/pages/accounts_list.py +++ b/modules/societegenerale/pages/accounts_list.py @@ -41,35 +41,44 @@ class AccountsList(BasePage): pass def get_list(self): + accounts = [] for tr in self.document.getiterator('tr'): - if 'LGNTableRow' in tr.attrib.get('class', '').split(): - account = Account() - for td in tr.getiterator('td'): - if td.attrib.get('headers', '') == 'TypeCompte': - a = td.find('a') - account.label = unicode(a.find("span").text) - account._link_id = a.get('href', '') + if not 'LGNTableRow' in tr.attrib.get('class', '').split(): + continue - elif td.attrib.get('headers', '') == 'NumeroCompte': - id = td.text - id = id.replace(u'\xa0','') - account.id = id + account = Account() + for td in tr.getiterator('td'): + if td.attrib.get('headers', '') == 'TypeCompte': + a = td.find('a') + account.label = unicode(a.find("span").text) + account._link_id = a.get('href', '') - elif td.attrib.get('headers', '') == 'Libelle': - pass + elif td.attrib.get('headers', '') == 'NumeroCompte': + id = td.text + id = id.replace(u'\xa0','') + account.id = id - elif td.attrib.get('headers', '') == 'Solde': - balance = td.find('div').text - if balance != None: - balance = balance.replace(u'\xa0','').replace(',','.') - account.balance = Decimal(balance) - else: - account.balance = Decimal(0) + elif td.attrib.get('headers', '') == 'Libelle': + pass - if 'CARTE_CB' in account._link_id: - continue + elif td.attrib.get('headers', '') == 'Solde': + balance = td.find('div').text + if balance != None: + balance = balance.replace(u'\xa0','').replace(',','.') + account.balance = Decimal(balance) + else: + account.balance = Decimal(0) - yield account + if 'CARTE_' in account._link_id: + ac = accounts[0] + ac._card_links.append(account._link_id) + if not ac.coming: + ac.coming = Decimal('0.0') + ac.coming += account.balance + else: + account._card_links = [] + accounts.append(account) + return iter(accounts) class Transaction(FrenchTransaction): PATTERNS = [(re.compile(r'^CARTE \w+ RETRAIT DAB.* (?P
\d{2})/(?P\d{2})( (?P\d+)H(?P\d+))? (?P.*)'), @@ -80,6 +89,8 @@ class Transaction(FrenchTransaction): FrenchTransaction.TYPE_PAYBACK), (re.compile(r'^(?PCARTE) \w+ (?P
\d{2})/(?P\d{2}) (?P.*)'), FrenchTransaction.TYPE_CARD), + (re.compile(r'^(?P
\d{2})(?P\d{2})/(?P.*?)/?(-[\d,]+)?$'), + FrenchTransaction.TYPE_CARD), (re.compile(r'^(?P(COTISATION|PRELEVEMENT|TELEREGLEMENT|TIP)) (?P.*)'), FrenchTransaction.TYPE_ORDER), (re.compile(r'^(?PVIR(EMEN)?T? \w+) (?P.*)'), @@ -104,7 +115,7 @@ class AccountHistory(BasePage): return None - def iter_transactions(self): + def iter_transactions(self, coming): url = self.get_part_url() if url is None: # There are no transactions in this kind of account @@ -121,7 +132,9 @@ class AccountHistory(BasePage): s = StringIO(unicode(el.text).encode('iso-8859-1')) doc = self.browser.get_document(s) - for tr in self._iter_transactions(doc): + for tr in self._iter_transactions(doc, coming): + if not tr._coming: + coming = False yield tr el = d.xpath('//dataHeader')[0] @@ -134,16 +147,31 @@ class AccountHistory(BasePage): operationNumberPG=el.find('operationNumber').text, operationTypePG=el.find('operationType').text, pageNumberPG=el.find('pageNumber').text, - idecrit=el.find('idecrit').text, + idecrit=el.find('idecrit').text or '', sign=p['sign'][0], src=p['src'][0]) - def _iter_transactions(self, doc): + def _iter_transactions(self, doc, coming): for i, tr in enumerate(self.parser.select(doc.getroot(), 'tr')): + date = tr.xpath('./td[@headers="Date"]')[0].text.strip() + if date == '': + coming = False + continue + + try: + raw = tr.attrib['title'].strip() + except KeyError: + raw = tr.xpath('./td[@headers="Libelle"]//text()')[0].strip() t = Transaction(i) - t.parse(date=tr.xpath('./td[@headers="Date"]')[0].text, - raw=tr.attrib['title'].strip()) + t.parse(date=date, raw=raw) t.set_amount(*reversed([el.text for el in tr.xpath('./td[@class="right"]')])) - t._coming = tr.xpath('./td[@headers="AVenir"]')[0].find('img') is not None + try: + t._coming = tr.xpath('./td[@headers="AVenir"]')[0].find('img') is not None + except IndexError: + t._coming = coming + + if t.label.startswith('DEBIT MENSUEL CARTE'): + continue + yield t