diff --git a/modules/creditdunord/browser.py b/modules/creditdunord/browser.py
index 3a0da917..de464787 100644
--- a/modules/creditdunord/browser.py
+++ b/modules/creditdunord/browser.py
@@ -23,7 +23,7 @@ import urllib
from weboob.tools.browser import BaseBrowser, BrowserIncorrectPassword
-from .pages import LoginPage, AccountsPage, TransactionsPage
+from .pages import LoginPage, AccountsPage, ProAccountsPage, TransactionsPage, ProTransactionsPage
__all__ = ['CreditDuNordBrowser']
@@ -35,8 +35,11 @@ class CreditDuNordBrowser(BaseBrowser):
PAGES = {'https://[^/]+/?': LoginPage,
'https://[^/]+/.*\?.*_pageLabel=page_erreur_connexion': LoginPage,
'https://[^/]+/vos-comptes/particuliers(\?.*)?': AccountsPage,
- 'https://[^/]+/vos-comptes/.*/transac/.*': TransactionsPage,
+ 'https://[^/]+/vos-comptes/.*/transac/particuliers.*': TransactionsPage,
+ 'https://[^/]+/vos-comptes/professionnels.*': ProAccountsPage,
+ 'https://[^/]+/vos-comptes/.*/transac/professionnels.*': ProTransactionsPage,
}
+ account_type = 'particuliers'
def __init__(self, website, *args, **kwargs):
self.DOMAIN = website
@@ -47,11 +50,9 @@ class CreditDuNordBrowser(BaseBrowser):
def home(self):
if self.is_logged():
- self.location(self.buildurl('/vos-comptes/particuliers'))
+ self.location(self.buildurl('/vos-comptes/%s' % self.account_type))
else:
self.login()
- return
- return self.location(self.buildurl('/vos-comptes/particuliers'))
def login(self):
assert isinstance(self.username, basestring)
@@ -79,9 +80,13 @@ class CreditDuNordBrowser(BaseBrowser):
if not self.is_logged():
raise BrowserIncorrectPassword()
+ m = re.match('https://[^/]+/vos-comptes/(\w+).*', self.page.url)
+ if m:
+ self.account_type = m.group(1)
+
def get_accounts_list(self):
if not self.is_on_page(AccountsPage):
- self.location(self.buildurl('/vos-comptes/particuliers'))
+ self.location(self.buildurl('/vos-comptes/%s' % self.account_type))
return self.page.get_list()
def get_account(self, id):
@@ -94,20 +99,12 @@ class CreditDuNordBrowser(BaseBrowser):
return None
- def iter_transactions(self, link, link_id, execution, is_coming=None):
- if link_id is None:
+ def iter_transactions(self, link, args, is_coming=None):
+ if args is None:
return
- event = 'clicDetailCompte'
- while 1:
- data = {'_eventId': event,
- '_ipc_eventValue': '',
- '_ipc_fireEvent': '',
- 'deviseAffichee': 'DEVISE',
- 'execution': execution,
- 'idCompteClique': link_id,
- }
- self.location(link, urllib.urlencode(data))
+ while args is not None:
+ self.location(link, urllib.urlencode(args))
assert self.is_on_page(TransactionsPage)
@@ -116,22 +113,17 @@ class CreditDuNordBrowser(BaseBrowser):
for tr in self.page.get_history():
yield tr
- is_last = self.page.is_last()
- if is_last:
- return
-
- event = 'clicChangerPageSuivant'
- execution = self.page.get_execution()
is_coming = self.page.is_coming
+ args = self.page.get_next_args(args)
def get_history(self, account):
- for tr in self.iter_transactions(account._link, account._link_id, account._execution):
+ for tr in self.iter_transactions(account._link, account._args):
yield tr
for tr in self.get_card_operations(account):
yield tr
def get_card_operations(self, account):
- for link_id in account._card_ids:
- for tr in self.iter_transactions(account._link, link_id, account._execution, True):
+ for link_args in account._card_ids:
+ for tr in self.iter_transactions(account._link, link_args, True):
yield tr
diff --git a/modules/creditdunord/pages.py b/modules/creditdunord/pages.py
index 17712f9a..afe33cb1 100644
--- a/modules/creditdunord/pages.py
+++ b/modules/creditdunord/pages.py
@@ -18,6 +18,7 @@
# along with weboob. If not, see .
+from urllib import quote
from decimal import Decimal
import re
from cStringIO import StringIO
@@ -97,14 +98,19 @@ class AccountsPage(CDNBasePage):
a.label = self.parser.tocleanstring(self.parser.parse(fp, self.browser.ENCODING).xpath('//div[@class="libelleCompteTDB"]')[0])
a.balance = Decimal(FrenchTransaction.clean_amount(line[self.COL_BALANCE]))
a._link = self.get_history_link()
- a._execution = self.get_execution()
if line[self.COL_HISTORY] == 'true':
- a._link_id = line[self.COL_ID]
+ a._args = {'_eventId': 'clicDetailCompte',
+ '_ipc_eventValue': '',
+ '_ipc_fireEvent': '',
+ 'deviseAffichee': 'DEVISE',
+ 'execution': self.get_execution(),
+ 'idCompteClique': line[self.COL_ID],
+ }
else:
- a._link_id = None
+ a._args = None
if a.id.find('_CarteVisa') >= 0:
- accounts[0]._card_ids.append(a._link_id)
+ accounts[0]._card_ids.append(a._args)
if not accounts[0].coming:
accounts[0].coming = Decimal('0.0')
accounts[0].coming += a.balance
@@ -116,6 +122,45 @@ class AccountsPage(CDNBasePage):
return iter(accounts)
+class ProAccountsPage(AccountsPage):
+ COL_ID = 0
+ COL_BALANCE = 1
+
+ ARGS = ['Banque', 'Agence', 'classement', 'Serie', 'SSCompte', 'Devise', 'CodeDeviseCCB', 'LibelleCompte', 'IntituleCompte', 'Indiceclassement', 'IndiceCompte', 'NomClassement']
+ def params_from_js(self, text):
+ l = []
+ for sub in re.findall("'([^']*)'", text):
+ l.append(sub)
+
+ url = '/vos-comptes/IPT/appmanager/transac/professionnels?_nfpb=true&_windowLabel=portletInstance_18&_pageLabel=page_synthese_v1' + '&_cdnCltUrl=' + "/transacClippe/" + quote(l.pop(0))
+ args = {}
+
+ for i, key in enumerate(self.ARGS):
+ args[key] = l[self.ARGS.index(key)]
+
+ return url, args
+
+
+ def get_list(self):
+ for tr in self.document.xpath('//table[@class="datas"]//tr'):
+ if tr.attrib.get('class', '') == 'entete':
+ continue
+
+ cols = tr.findall('td')
+
+ a = Account()
+ a.id = cols[self.COL_ID].xpath('.//span[@class="right-underline"]')[0].text.strip()
+ a.label = unicode(cols[self.COL_ID].xpath('.//span[@class="left-underline"]')[0].text.strip())
+ balance = self.parser.tocleanstring(cols[self.COL_BALANCE])
+ a.balance = Decimal(FrenchTransaction.clean_amount(balance))
+ a.currency = a.get_currency(balance)
+ a._link, a._args = self.params_from_js(cols[self.COL_ID].find('a').attrib['href'])
+
+ a._card_ids = []
+
+ yield a
+
+
class Transaction(FrenchTransaction):
PATTERNS = [(re.compile(r'^(?PRET DAB \w+ .*?) LE (?P\d{2})(?P\d{2})$'),
FrenchTransaction.TYPE_WITHDRAWAL),
@@ -143,6 +188,15 @@ class TransactionsPage(CDNBasePage):
is_coming = None
+ def get_next_args(self, args):
+ if self.is_last():
+ return None
+
+ args['_eventId'] = 'clicChangerPageSuivant'
+ args['execution'] = self.get_execution()
+ args.pop('idCompteClique', None)
+ return args
+
def is_last(self):
for script in self.document.xpath('//script'):
txt = script.text
@@ -154,11 +208,28 @@ class TransactionsPage(CDNBasePage):
return True
+ def set_coming(self, t):
+ if self.is_coming is not None and t.raw.startswith('TOTAL DES') and t.amount > 0:
+ # ignore card credit and next transactions are already debited
+ self.is_coming = False
+ return True
+ if self.is_coming is None and t.raw.startswith('ACHATS CARTE'):
+ # Ignore card debit
+ return True
+
+ t._is_coming = bool(self.is_coming)
+ return False
+
def get_history(self):
txt = self.get_from_js('ListeMvts_data = new Array(', ');')
if txt is None:
- raise BrokenPageError('Unable to find transactions list in scripts')
+ no_trans = self.get_from_js('js_noMvts = new Ext.Panel(', ')')
+ if no_trans is not None:
+ # there is no transactions for this account, this is normal.
+ return
+ else:
+ raise BrokenPageError('Unable to find transactions list in scripts')
data = json.loads('[%s]' % txt.replace('"', '\\"').replace("'", '"'))
@@ -175,13 +246,49 @@ class TransactionsPage(CDNBasePage):
t.parse(date, raw)
t.set_amount(line[self.COL_VALUE])
- if self.is_coming is not None and raw.startswith('TOTAL DES') and t.amount > 0:
- # ignore card credit and next transactions are already debited
- self.is_coming = False
- continue
- if self.is_coming is None and raw.startswith('ACHATS CARTE'):
- # Ignore card debit
+ if self.set_coming(t):
+ continue
+
+ yield t
+
+class ProTransactionsPage(TransactionsPage):
+ def get_next_args(self, args):
+ txt = self.get_from_js('myPage.setPiedPage(oNavSuivantPrec_1(', ')')
+
+ if txt is None:
+ return None
+
+ l = txt.split(',')
+ if int(l[4]) <= 40:
+ return None
+
+ args['PageDemandee'] = int(args.get('PageDemandee', 1)) + 1
+ return args
+
+ def parse_transactions(self):
+ transactions = {}
+ for script in self.document.xpath('//script'):
+ txt = script.text
+ if txt is None:
+ continue
+
+ for i, key, value in re.findall('listeopecv\[(\d+)\]\[\'(\w+)\'\]="(.*)";', txt):
+ i = int(i)
+ if not i in transactions:
+ transactions[i] = {}
+ transactions[i][key] = value
+
+ return transactions.iteritems()
+
+ def get_history(self):
+ for i, tr in self.parse_transactions():
+ t = Transaction(i)
+ date = tr['date']
+ raw = self.parser.strip('%s
' % (' '.join([tr['typeope'], tr['LibComp']])))
+ t.parse(date, raw)
+ t.set_amount(tr['mont'])
+
+ if self.set_coming(t):
continue
- t._is_coming = bool(self.is_coming)
yield t