diff --git a/modules/societegenerale/backend.py b/modules/societegenerale/backend.py
index b7ad32b0..2c5f6d87 100644
--- a/modules/societegenerale/backend.py
+++ b/modules/societegenerale/backend.py
@@ -51,7 +51,6 @@ class SocieteGeneraleBackend(BaseBackend, ICapBank):
yield account
def get_account(self, _id):
- print _id
if not _id.isdigit():
raise AccountNotFound()
with self.browser:
@@ -60,3 +59,15 @@ class SocieteGeneraleBackend(BaseBackend, ICapBank):
return account
else:
raise AccountNotFound()
+
+ def iter_history(self, account):
+ with self.browser:
+ for tr in self.browser.iter_history(account._link_id):
+ if not tr._coming:
+ yield tr
+
+ def iter_coming(self, account):
+ with self.browser:
+ for tr in self.browser.iter_history(account._link_id):
+ if tr._coming:
+ yield tr
diff --git a/modules/societegenerale/browser.py b/modules/societegenerale/browser.py
index 8cac7f3d..92c1bf08 100644
--- a/modules/societegenerale/browser.py
+++ b/modules/societegenerale/browser.py
@@ -19,7 +19,9 @@
from weboob.tools.browser import BaseBrowser, BrowserIncorrectPassword
-from .pages import LoginPage, AccountsList, BadLoginPage
+
+from .pages.accounts_list import AccountsList, AccountHistory
+from .pages.login import LoginPage, BadLoginPage
__all__ = ['SocieteGenerale']
@@ -34,7 +36,7 @@ class SocieteGenerale(BaseBrowser):
'https://particuliers.societegenerale.fr/.*': LoginPage,
'https://.*.societegenerale.fr//acces/authlgn.html': BadLoginPage,
'.*restitution/cns_listeprestation.html': AccountsList,
-# '.*restitution/cns_detailCav.html.*': AccountHistory,
+ '.*restitution/cns_detailCav.html.*': AccountHistory,
}
def __init__(self, *args, **kwargs):
@@ -79,12 +81,11 @@ class SocieteGenerale(BaseBrowser):
return None
- def get_history(self, account):
- raise NotImplementedError()
+ def iter_history(self, url):
+ self.location(url)
- #if not self.is_on_page(AccountHistory) or self.page.account.id != account.id:
- # self.location(account._link_id)
- #return self.page.get_operations()
+ assert self.is_on_page(AccountHistory)
+ #self.location(self.page.get_part_url())
- def transfer(self, from_id, to_id, amount, reason=None):
- raise NotImplementedError()
+ #assert self.is_on_page(AccountHistoryPart)
+ return self.page.iter_transactions()
diff --git a/modules/societegenerale/pages/__init__.py b/modules/societegenerale/pages/__init__.py
index fb752cd3..96817e16 100644
--- a/modules/societegenerale/pages/__init__.py
+++ b/modules/societegenerale/pages/__init__.py
@@ -18,14 +18,12 @@
# along with weboob. If not, see .
-from .accounts_list import AccountsList
+from .accounts_list import AccountsList, AccountHistory
from .login import LoginPage, BadLoginPage
-class AccountPrelevement(AccountsList):
- pass
-
__all__ = ['LoginPage',
'BadLoginPage',
'AccountsList',
+ 'AccountHistory',
]
diff --git a/modules/societegenerale/pages/accounts_list.py b/modules/societegenerale/pages/accounts_list.py
index 0ee17d07..85a4fd04 100644
--- a/modules/societegenerale/pages/accounts_list.py
+++ b/modules/societegenerale/pages/accounts_list.py
@@ -18,11 +18,19 @@
# along with weboob. If not, see .
+from urlparse import parse_qs, urlparse
+from lxml.etree import XML
+from cStringIO import StringIO
from decimal import Decimal
import re
from weboob.capabilities.bank import Account
-from weboob.tools.browser import BasePage
+from weboob.tools.capabilities.bank.transactions import FrenchTransaction
+from weboob.tools.browser import BasePage, BrokenPageError
+
+
+__all__ = ['AccountsList', 'AccountHistory']
+
class AccountsList(BasePage):
LINKID_REGEXP = re.compile(".*ch4=(\w+).*")
@@ -38,7 +46,7 @@ class AccountsList(BasePage):
for td in tr.getiterator('td'):
if td.attrib.get('headers', '') == 'TypeCompte':
a = td.find('a')
- account.label = a.find("span").text
+ account.label = unicode(a.find("span").text)
account._link_id = a.get('href', '')
elif td.attrib.get('headers', '') == 'NumeroCompte':
@@ -60,3 +68,85 @@ class AccountsList(BasePage):
l.append(account)
return l
+
+class Transaction(FrenchTransaction):
+ PATTERNS = [(re.compile(r'^CARTE \w+ RETRAIT DAB.* (?P
\d{2})/(?P\d{2}) (?P\d+)H(?P\d+) (?P.*)'),
+ FrenchTransaction.TYPE_WITHDRAWAL),
+ (re.compile(r'^(?PCARTE) \w+ (?P\d{2})/(?P\d{2}) (?P.*)'),
+ FrenchTransaction.TYPE_CARD),
+ (re.compile(r'^(?P(COTISATION|PRELEVEMENT|TELEREGLEMENT|TIP)) (?P.*)'),
+ FrenchTransaction.TYPE_ORDER),
+ (re.compile(r'^(?PVIR(EMEN)?T? \w+) (?P.*)'),
+ FrenchTransaction.TYPE_TRANSFER),
+ (re.compile(r'^(CHEQUE) (?P.*)'), FrenchTransaction.TYPE_CHECK),
+ (re.compile(r'^(FRAIS) (?P.*)'), FrenchTransaction.TYPE_BANK),
+ (re.compile(r'^(?PECHEANCEPRET)(?P.*)'),
+ FrenchTransaction.TYPE_LOAN_PAYMENT),
+ (re.compile(r'^(?PREMISE CHEQUES)(?P.*)'),
+ FrenchTransaction.TYPE_DEPOSIT),
+ ]
+
+class AccountHistory(BasePage):
+ def get_part_url(self):
+ for script in self.document.getiterator('script'):
+ if script.text is None:
+ continue
+
+ m = re.search('var listeEcrCavXmlUrl="(.*)";', script.text)
+ if m:
+ return m.group(1)
+
+ raise BrokenPageError('Unable to find link to history part')
+
+ def iter_transactions(self):
+ url = self.get_part_url()
+ while 1:
+ d = XML(self.browser.readurl(url))
+ el = d.xpath('//dataBody')[0]
+ s = StringIO(el.text)
+ doc = self.browser.get_document(s)
+
+ for tr in self._iter_transactions(doc):
+ yield tr
+
+ el = d.xpath('//dataHeader')[0]
+ if int(el.find('suite').text) != 1:
+ return
+
+ url = urlparse(url)
+ p = parse_qs(url.query)
+ url = self.browser.buildurl(url.path, n10_nrowcolor=0,
+ operationNumberPG=el.find('operationNumber').text,
+ operationTypePG=el.find('operationType').text,
+ pageNumberPG=el.find('pageNumber').text,
+ sign=p['sign'][0],
+ src=p['src'][0])
+
+
+ def _iter_transactions(self, doc):
+ for i, tr in enumerate(self.parser.select(doc.getroot(), 'tr')):
+ t = Transaction(i)
+ t.parse(date=tr.xpath('./td[@headers="Date"]')[0].text,
+ raw=tr.attrib['title'].strip())
+ t.set_amount(*reversed([el.text for el in tr.xpath('./td[@class="right"]')]))
+ t._coming = tr.xpath('./td[@headers="AVenir"]')[0].text
+ yield t
+
+
+class _AccountHistory(BasePage):
+ def iter_operations(self):
+ for tr in self.document.xpath('//table[@id="tableCompte"]//tr'):
+ if len(tr.xpath('td[@class="debit"]')) == 0:
+ continue
+
+ id = tr.find('td').find('input').attrib['value']
+ op = Transaction(id)
+ op.parse(date=tr.findall('td')[1].text,
+ raw=tr.findall('td')[2].text.replace(u'\xa0', u''))
+
+ debit = tr.xpath('.//td[@class="debit"]')[0].text
+ credit = tr.xpath('.//td[@class="credit"]')[0].text
+
+ op.set_amount(credit, debit)
+
+ yield op