diff --git a/modules/bnporc/backend.py b/modules/bnporc/backend.py
index 8a8725ee..41d322ec 100644
--- a/modules/bnporc/backend.py
+++ b/modules/bnporc/backend.py
@@ -89,11 +89,11 @@ class BNPorcBackend(BaseBackend, ICapBank, ICapMessages):
def iter_history(self, account):
with self.browser:
- return self.browser.iter_history(account._link_id)
+ return self.browser.iter_history(account)
def iter_coming(self, account):
with self.browser:
- return self.browser.iter_coming_operations(account._link_id)
+ return self.browser.iter_coming_operations(account)
def iter_transfer_recipients(self, ignored):
for account in self.browser.get_transfer_accounts().itervalues():
diff --git a/modules/bnporc/browser.py b/modules/bnporc/browser.py
index 2974e137..818880ee 100644
--- a/modules/bnporc/browser.py
+++ b/modules/bnporc/browser.py
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
-# Copyright(C) 2009-2012 Romain Bignon
+# Copyright(C) 2009-2013 Romain Bignon
#
# This file is part of weboob.
#
@@ -24,12 +24,14 @@ from logging import warning
from weboob.tools.browser import BaseBrowser, BrowserIncorrectPassword, BrowserPasswordExpired
from weboob.capabilities.bank import TransferError, Transfer
-from .pages import AccountsList, AccountHistory, ChangePasswordPage, \
- AccountComing, AccountPrelevement, TransferPage, \
- TransferConfirmPage, TransferCompletePage, \
- LoginPage, ConfirmPage, InfoMessagePage, \
- MessagePage, MessagesPage
+from .perso.accounts_list import AccountsList, AccountPrelevement
+from .perso.transactions import AccountHistory, AccountComing
+from .perso.transfer import TransferPage, TransferConfirmPage, TransferCompletePage
+from .perso.login import LoginPage, ConfirmPage, ChangePasswordPage, InfoMessagePage
+from .perso.messages import MessagePage, MessagesPage
+
+from .pro import ProAccountsList, ProAccountHistory
__all__ = ['BNPorc']
@@ -54,6 +56,11 @@ class BNPorc(BaseBrowser):
'.*Action=DSP_MSG.*': InfoMessagePage,
'.*MessagesRecus.*': MessagesPage,
'.*BmmFicheLireMessage.*': MessagePage,
+
+ # Pro
+ 'https?://www.secure.bnpparibas.net/banque/portail/entrepros/Fiche\?.*identifiant=PRO_Une_Comptes.*': ProAccountsList,
+ 'https?://www.secure.bnpparibas.net/SAF_ROP\?Origine=DSP_HISTOCPT.*': ProAccountHistory,
+ 'https?://www.secure.bnpparibas.net/SAF_ROP\?Origine=DSP_ET.*': ProAccountHistory,
}
def __init__(self, *args, **kwargs):
@@ -140,75 +147,85 @@ class BNPorc(BaseBrowser):
return None
- def iter_history(self, id):
- if id is None:
+ def iter_history(self, account):
+ if account._link_id is None:
return iter([])
- if not self.is_on_page(AccountsList):
- self.location('/NSFR?Action=DSP_VGLOBALE')
+ if account._stp is not None:
+ # Pro
+ self.location(self.buildurl('/SAF_ROP', Origine='DSP_HISTOCPT', ch4=account._link_id, stp=account._stp))
+ else:
+ # Perso
+ if not self.is_on_page(AccountsList):
+ self.location('/NSFR?Action=DSP_VGLOBALE')
- execution = self.page.document.xpath('//form[@name="goToApplication"]/input[@name="execution"]')[0].attrib['value']
- data = {'gt': 'homepage:basic-theme',
- 'externalIAId': 'IAStatements',
- 'cboFlowName': 'flow/iastatement',
- 'contractId': id,
- 'groupId': '-2',
- 'pastOrPendingOperations': 1,
- 'groupSelected':'-2',
- 'step': 'STAMENTS',
- 'pageId': 'releveoperations',
- #'operationsPerPage': 100,
- #'_eventId': 'changeOperationsPerPage',
- 'sendEUD': 'true',
- 'execution': execution,
- }
+ execution = self.page.document.xpath('//form[@name="goToApplication"]/input[@name="execution"]')[0].attrib['value']
+ data = {'gt': 'homepage:basic-theme',
+ 'externalIAId': 'IAStatements',
+ 'cboFlowName': 'flow/iastatement',
+ 'contractId': account._link_id,
+ 'groupId': '-2',
+ 'pastOrPendingOperations': 1,
+ 'groupSelected':'-2',
+ 'step': 'STAMENTS',
+ 'pageId': 'releveoperations',
+ #'operationsPerPage': 100,
+ #'_eventId': 'changeOperationsPerPage',
+ 'sendEUD': 'true',
+ 'execution': execution,
+ }
- self.location('https://www.secure.bnpparibas.net/banque/portail/particulier/FicheA', urllib.urlencode(data))
+ self.location('https://www.secure.bnpparibas.net/banque/portail/particulier/FicheA', urllib.urlencode(data))
- execution = self.page.document.xpath('//form[@name="displayStatementForm"]/input[@name="_flowExecutionKey"]')[0].attrib['value']
- data = {'_eventId': 'changeOperationsPerPage',
- 'newCategoryId': '',
- 'categorisationInProgress': '',
- 'contractId': id,
- '_flowExecutionKey': execution,
- 'groupId': '-2',
- 'operations.objectsPerPage': 100,
- 'operations.pageNumber': 1,
- 'pageId': 'releveoperations',
- }
+ execution = self.page.document.xpath('//form[@name="displayStatementForm"]/input[@name="_flowExecutionKey"]')[0].attrib['value']
+ data = {'_eventId': 'changeOperationsPerPage',
+ 'newCategoryId': '',
+ 'categorisationInProgress': '',
+ 'contractId': account._link_id,
+ '_flowExecutionKey': execution,
+ 'groupId': '-2',
+ 'operations.objectsPerPage': 100,
+ 'operations.pageNumber': 1,
+ 'pageId': 'releveoperations',
+ }
- # it's not a joke, BNP guys are really crappy.
- for i in xrange(30):
- data['_operations.list[%d].checkedOff' % i] = 'on'
- data['_operations.list[%d].selectedForCategorization' % i] = 'on'
- self.location('https://www.secure.bnpparibas.net/banque/portail/particulier/FicheA', urllib.urlencode(data))
+ # it's not a joke, BNP guys are really crappy.
+ for i in xrange(30):
+ data['_operations.list[%d].checkedOff' % i] = 'on'
+ data['_operations.list[%d].selectedForCategorization' % i] = 'on'
+ self.location('https://www.secure.bnpparibas.net/banque/portail/particulier/FicheA', urllib.urlencode(data))
return self.page.iter_operations()
- def iter_coming_operations(self, id):
- if id is None:
+ def iter_coming_operations(self, account):
+ if account._link_id is None:
return iter([])
- if not self.is_on_page(AccountsList):
- self.location('/NSFR?Action=DSP_VGLOBALE')
+ if account._stp is not None:
+ # Pro
+ self.location(self.buildurl('/SAF_ROP', Origine='DSP_ET', ch4=account._link_id, stp=account._stp))
+ else:
+ # Persô
+ if not self.is_on_page(AccountsList):
+ self.location('/NSFR?Action=DSP_VGLOBALE')
- execution = self.page.document.xpath('//form[@name="goToApplication"]/input[@name="execution"]')[0].attrib['value']
- data = {'gt': 'homepage:basic-theme',
- 'externalIAId': 'IAStatements',
- 'cboFlowName': 'flow/iastatement',
- 'contractId': id,
- 'groupId': '-2',
- 'pastOrPendingOperations': 2,
- 'groupSelected':'-2',
- 'step': 'STAMENTS',
- 'pageId': 'mouvementsavenir',
- #'operationsPerPage': 100,
- #'_eventId': 'changeOperationsPerPage',
- 'sendEUD': 'true',
- 'execution': execution,
- }
+ execution = self.page.document.xpath('//form[@name="goToApplication"]/input[@name="execution"]')[0].attrib['value']
+ data = {'gt': 'homepage:basic-theme',
+ 'externalIAId': 'IAStatements',
+ 'cboFlowName': 'flow/iastatement',
+ 'contractId': account._link_id,
+ 'groupId': '-2',
+ 'pastOrPendingOperations': 2,
+ 'groupSelected':'-2',
+ 'step': 'STAMENTS',
+ 'pageId': 'mouvementsavenir',
+ #'operationsPerPage': 100,
+ #'_eventId': 'changeOperationsPerPage',
+ 'sendEUD': 'true',
+ 'execution': execution,
+ }
- self.location('https://www.secure.bnpparibas.net/banque/portail/particulier/FicheA', urllib.urlencode(data))
+ self.location('https://www.secure.bnpparibas.net/banque/portail/particulier/FicheA', urllib.urlencode(data))
return self.page.iter_coming_operations()
diff --git a/modules/bnporc/pages/__init__.py b/modules/bnporc/pages/__init__.py
deleted file mode 100644
index 26840954..00000000
--- a/modules/bnporc/pages/__init__.py
+++ /dev/null
@@ -1,32 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Copyright(C) 2009-2012 Romain Bignon
-#
-# This file is part of weboob.
-#
-# weboob is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# weboob is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with weboob. If not, see .
-
-
-from .accounts_list import AccountsList
-from .transactions import AccountHistory, AccountComing
-from .transfer import TransferPage, TransferConfirmPage, TransferCompletePage
-from .login import LoginPage, ConfirmPage, ChangePasswordPage, InfoMessagePage
-from .messages import MessagePage, MessagesPage
-
-class AccountPrelevement(AccountsList): pass
-
-__all__ = ['AccountsList', 'AccountComing', 'AccountHistory', 'LoginPage',
- 'ConfirmPage', 'InfoMessagePage', 'AccountPrelevement', 'ChangePasswordPage',
- 'TransferPage', 'TransferConfirmPage', 'TransferCompletePage',
- 'MessagePage', 'MessagesPage']
diff --git a/modules/bnporc/perso/__init__.py b/modules/bnporc/perso/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/modules/bnporc/pages/accounts_list.py b/modules/bnporc/perso/accounts_list.py
similarity index 96%
rename from modules/bnporc/pages/accounts_list.py
rename to modules/bnporc/perso/accounts_list.py
index 3141754e..295bf4bc 100644
--- a/modules/bnporc/pages/accounts_list.py
+++ b/modules/bnporc/perso/accounts_list.py
@@ -26,7 +26,7 @@ from weboob.capabilities.bank import Account
from weboob.capabilities.base import NotAvailable
from weboob.tools.browser import BasePage, BrokenPageError, BrowserPasswordExpired
-__all__ = ['AccountsList']
+__all__ = ['AccountsList', 'AccountPrelevement']
class AccountsList(BasePage):
@@ -53,6 +53,9 @@ class AccountsList(BasePage):
def _parse_account(self, tr):
account = Account()
+ # for pro usage
+ account._stp = None
+
account.id = tr.xpath('.//td[@class="libelleCompte"]/input')[0].attrib['id'][len('libelleCompte'):]
if len(str(account.id)) == 23:
account.id = str(account.id)[5:21]
@@ -107,3 +110,7 @@ class AccountsList(BasePage):
if 'MessagesRecus' in link.attrib.get('href', ''):
return link.attrib['href']
raise BrokenPageError('Unable to find the link to the messages page')
+
+
+class AccountPrelevement(AccountsList):
+ pass
diff --git a/modules/bnporc/pages/login.py b/modules/bnporc/perso/login.py
similarity index 100%
rename from modules/bnporc/pages/login.py
rename to modules/bnporc/perso/login.py
diff --git a/modules/bnporc/pages/messages.py b/modules/bnporc/perso/messages.py
similarity index 100%
rename from modules/bnporc/pages/messages.py
rename to modules/bnporc/perso/messages.py
diff --git a/modules/bnporc/pages/transactions.py b/modules/bnporc/perso/transactions.py
similarity index 100%
rename from modules/bnporc/pages/transactions.py
rename to modules/bnporc/perso/transactions.py
diff --git a/modules/bnporc/pages/transfer.py b/modules/bnporc/perso/transfer.py
similarity index 100%
rename from modules/bnporc/pages/transfer.py
rename to modules/bnporc/perso/transfer.py
diff --git a/modules/bnporc/pro.py b/modules/bnporc/pro.py
new file mode 100644
index 00000000..023bef6c
--- /dev/null
+++ b/modules/bnporc/pro.py
@@ -0,0 +1,86 @@
+# -*- coding: utf-8 -*-
+
+# Copyright(C) 2009-2013 Romain Bignon
+#
+# This file is part of weboob.
+#
+# weboob is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# weboob is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with weboob. If not, see .
+
+
+import re
+from urlparse import urlparse, parse_qsl
+from decimal import Decimal
+
+from weboob.capabilities.bank import Account
+from weboob.tools.browser import BasePage
+
+from .perso.transactions import Transaction
+
+
+__all__ = ['ProAccountsList', 'ProAccountHistory']
+
+
+class ProAccountsList(BasePage):
+ COL_LABEL = 1
+ COL_ID = 2
+ COL_BALANCE = 3
+ COL_COMING = 5
+ def get_list(self):
+ for tr in self.document.xpath('//tr[@class="comptes"]'):
+ cols = tr.findall('td')
+
+ account = Account()
+ account.id = self.parser.tocleanstring(cols[self.COL_ID])
+ account.label = self.parser.tocleanstring(cols[self.COL_LABEL])
+ account.balance = Decimal(self.parser.tocleanstring(cols[self.COL_BALANCE]))
+ account.coming = Decimal(self.parser.tocleanstring(cols[self.COL_COMING]))
+ account._link_id = None
+ account._stp = None
+
+ a = cols[self.COL_LABEL].find('a')
+ if a is not None:
+ url = urlparse(a.attrib['href'])
+ p = dict(parse_qsl(url.query))
+ account._link_id = p.get('ch4', None)
+ account._stp = p.get('stp', None)
+
+ yield account
+
+class ProAccountHistory(BasePage):
+ COL_DATE = 0
+ COL_LABEL = 1
+ COL_DEBIT = -2
+ COL_CREDIT = -1
+
+ def iter_operations(self):
+ for i, tr in enumerate(self.document.xpath('//tr[@class="hdoc1" or @class="hdotc1"]')):
+ if 'bgcolor' not in tr.attrib:
+ continue
+ cols = tr.findall('td')
+
+ op = Transaction(i)
+
+ date = self.parser.tocleanstring(cols[self.COL_DATE])
+ raw = self.parser.tocleanstring(cols[self.COL_LABEL])
+ raw = re.sub(r'[ \xa0]+', ' ', raw).strip()
+ op.parse(date=date, raw=raw)
+
+ debit = self.parser.tocleanstring(cols[self.COL_DEBIT])
+ credit = self.parser.tocleanstring(cols[self.COL_CREDIT])
+ op.set_amount(credit, debit)
+
+ yield op
+
+ def iter_coming_operations(self):
+ raise NotImplementedError()