support pro accounts

This commit is contained in:
Romain Bignon 2013-03-12 13:04:25 +01:00
commit a8d8147452
10 changed files with 179 additions and 101 deletions

View file

@ -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():

View file

@ -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()

View file

@ -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 <http://www.gnu.org/licenses/>.
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']

View file

View file

@ -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

86
modules/bnporc/pro.py Normal file
View file

@ -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 <http://www.gnu.org/licenses/>.
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()