bnporc: introduce Enterprise option
Not working for now
This commit is contained in:
parent
db9f2d6d73
commit
6594ec2288
4 changed files with 131 additions and 11 deletions
|
|
@ -27,9 +27,10 @@ from datetime import datetime, timedelta
|
||||||
from weboob.capabilities.bank import ICapBank, AccountNotFound, Account, Recipient
|
from weboob.capabilities.bank import ICapBank, AccountNotFound, Account, Recipient
|
||||||
from weboob.capabilities.messages import ICapMessages, Thread
|
from weboob.capabilities.messages import ICapMessages, Thread
|
||||||
from weboob.tools.backend import BaseBackend, BackendConfig
|
from weboob.tools.backend import BaseBackend, BackendConfig
|
||||||
from weboob.tools.value import ValueBackendPassword
|
from weboob.tools.value import ValueBackendPassword, Value
|
||||||
|
|
||||||
from .browser import BNPorc
|
from .browser import BNPorc
|
||||||
|
from .enterprise.browser import BNPEnterprise
|
||||||
|
|
||||||
|
|
||||||
__all__ = ['BNPorcBackend']
|
__all__ = ['BNPorcBackend']
|
||||||
|
|
@ -42,12 +43,14 @@ class BNPorcBackend(BaseBackend, ICapBank, ICapMessages):
|
||||||
VERSION = '0.g'
|
VERSION = '0.g'
|
||||||
LICENSE = 'AGPLv3+'
|
LICENSE = 'AGPLv3+'
|
||||||
DESCRIPTION = 'BNP Paribas French bank website'
|
DESCRIPTION = 'BNP Paribas French bank website'
|
||||||
CONFIG = BackendConfig(ValueBackendPassword('login', label='Account ID', masked=False),
|
CONFIG = BackendConfig(
|
||||||
ValueBackendPassword('password', label='Password', regexp='^(\d{6}|)$'),
|
ValueBackendPassword('login', label='Account ID', masked=False),
|
||||||
ValueBackendPassword('rotating_password', default='',
|
ValueBackendPassword('password', label='Password', regexp='^(\d{6}|)$'),
|
||||||
label='Password to set when the allowed uses are exhausted (6 digits)',
|
ValueBackendPassword('rotating_password', default='',
|
||||||
regexp='^(\d{6}|)$'))
|
label='Password to set when the allowed uses are exhausted (6 digits)',
|
||||||
BROWSER = BNPorc
|
regexp='^(\d{6}|)$'),
|
||||||
|
Value('website', label='Website to use', default='pp',
|
||||||
|
choices={'pp': 'Particuliers/Profesionnels', 'ent': 'Entreprises'}))
|
||||||
STORAGE = {'seen': []}
|
STORAGE = {'seen': []}
|
||||||
|
|
||||||
# Store the messages *list* for this duration
|
# Store the messages *list* for this duration
|
||||||
|
|
@ -59,14 +62,20 @@ class BNPorcBackend(BaseBackend, ICapBank, ICapMessages):
|
||||||
self._threads_age = datetime.utcnow()
|
self._threads_age = datetime.utcnow()
|
||||||
|
|
||||||
def create_default_browser(self):
|
def create_default_browser(self):
|
||||||
|
b = {'pp': BNPorc, 'ent': BNPEnterprise}
|
||||||
|
self.BROWSER = b[self.config['website'].get()]
|
||||||
if self.config['rotating_password'].get().isdigit() and len(self.config['rotating_password'].get()) == 6:
|
if self.config['rotating_password'].get().isdigit() and len(self.config['rotating_password'].get()) == 6:
|
||||||
rotating_password = self.config['rotating_password'].get()
|
rotating_password = self.config['rotating_password'].get()
|
||||||
else:
|
else:
|
||||||
rotating_password = None
|
rotating_password = None
|
||||||
return self.create_browser(self.config['login'].get(),
|
if self.config['website'].get() != 'pp':
|
||||||
self.config['password'].get(),
|
return self.create_browser(self.config['login'].get(),
|
||||||
password_changed_cb=self._password_changed_cb,
|
self.config['password'].get())
|
||||||
rotating_password=rotating_password)
|
else:
|
||||||
|
return self.create_browser(self.config['login'].get(),
|
||||||
|
self.config['password'].get(),
|
||||||
|
password_changed_cb=self._password_changed_cb,
|
||||||
|
rotating_password=rotating_password)
|
||||||
|
|
||||||
def _password_changed_cb(self, old, new):
|
def _password_changed_cb(self, old, new):
|
||||||
self.config['password'].set(new)
|
self.config['password'].set(new)
|
||||||
|
|
@ -92,10 +101,16 @@ class BNPorcBackend(BaseBackend, ICapBank, ICapMessages):
|
||||||
return self.browser.iter_history(account)
|
return self.browser.iter_history(account)
|
||||||
|
|
||||||
def iter_coming(self, account):
|
def iter_coming(self, account):
|
||||||
|
if self.config['website'].get() != 'pp':
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
with self.browser:
|
with self.browser:
|
||||||
return self.browser.iter_coming_operations(account)
|
return self.browser.iter_coming_operations(account)
|
||||||
|
|
||||||
def iter_transfer_recipients(self, ignored):
|
def iter_transfer_recipients(self, ignored):
|
||||||
|
if self.config['website'].get() != 'pp':
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
for account in self.browser.get_transfer_accounts().itervalues():
|
for account in self.browser.get_transfer_accounts().itervalues():
|
||||||
recipient = Recipient()
|
recipient = Recipient()
|
||||||
recipient.id = account.id
|
recipient.id = account.id
|
||||||
|
|
@ -103,6 +118,9 @@ class BNPorcBackend(BaseBackend, ICapBank, ICapMessages):
|
||||||
yield recipient
|
yield recipient
|
||||||
|
|
||||||
def transfer(self, account, to, amount, reason=None):
|
def transfer(self, account, to, amount, reason=None):
|
||||||
|
if self.config['website'].get() != 'pp':
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
if isinstance(account, Account):
|
if isinstance(account, Account):
|
||||||
account = account.id
|
account = account.id
|
||||||
|
|
||||||
|
|
@ -141,6 +159,9 @@ class BNPorcBackend(BaseBackend, ICapBank, ICapMessages):
|
||||||
return self.get_thread(thread)
|
return self.get_thread(thread)
|
||||||
|
|
||||||
def get_thread(self, _id):
|
def get_thread(self, _id):
|
||||||
|
if self.config['website'].get() != 'pp':
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
if isinstance(_id, Thread):
|
if isinstance(_id, Thread):
|
||||||
thread = _id
|
thread = _id
|
||||||
_id = thread.id
|
_id = thread.id
|
||||||
|
|
@ -151,6 +172,9 @@ class BNPorcBackend(BaseBackend, ICapBank, ICapMessages):
|
||||||
return thread
|
return thread
|
||||||
|
|
||||||
def iter_unread_messages(self):
|
def iter_unread_messages(self):
|
||||||
|
if self.config['website'].get() != 'pp':
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
threads = list(self.iter_threads(cache=True))
|
threads = list(self.iter_threads(cache=True))
|
||||||
for thread in threads:
|
for thread in threads:
|
||||||
if thread.root.flags & thread.root.IS_UNREAD:
|
if thread.root.flags & thread.root.IS_UNREAD:
|
||||||
|
|
|
||||||
0
modules/bnporc/enterprise/__init__.py
Normal file
0
modules/bnporc/enterprise/__init__.py
Normal file
57
modules/bnporc/enterprise/browser.py
Normal file
57
modules/bnporc/enterprise/browser.py
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# Copyright(C) 2013 Laurent Bachelier
|
||||||
|
#
|
||||||
|
# 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 weboob.tools.browser import BaseBrowser, BrowserIncorrectPassword
|
||||||
|
|
||||||
|
from .pages import LoginPage, AccountsPage
|
||||||
|
|
||||||
|
__all__ = ['BNPEnterprise']
|
||||||
|
|
||||||
|
|
||||||
|
class BNPEnterprise(BaseBrowser):
|
||||||
|
DOMAIN = 'entreprisesplus.bnpparibas.net'
|
||||||
|
PROTOCOL = 'https'
|
||||||
|
CERTHASH = '423f68a8162d1328bacb48269675d8b8577ebcc9d222860de8421792c4d222c1'
|
||||||
|
|
||||||
|
PAGES = {'%s://%s/NSAccess.*' % (PROTOCOL, DOMAIN): LoginPage,
|
||||||
|
'%s://%s/UNE\?Action=DSP_VGLOBALE' % (PROTOCOL, DOMAIN): AccountsPage}
|
||||||
|
|
||||||
|
def home(self):
|
||||||
|
self.location('%s://%s/NSAccess' % (self.PROTOCOL, self.DOMAIN))
|
||||||
|
|
||||||
|
def is_logged(self):
|
||||||
|
if self.page:
|
||||||
|
if self.page.get_error() is not None:
|
||||||
|
return False
|
||||||
|
return not self.is_on_page(LoginPage)
|
||||||
|
|
||||||
|
def login(self):
|
||||||
|
assert isinstance(self.username, basestring)
|
||||||
|
assert isinstance(self.password, basestring)
|
||||||
|
assert self.password.isdigit()
|
||||||
|
|
||||||
|
if not self.is_on_page(LoginPage):
|
||||||
|
self.home()
|
||||||
|
|
||||||
|
self.page.login(self.username, self.password)
|
||||||
|
self.location('/UNE?Action=DSP_VGLOBALE', no_login=True)
|
||||||
|
|
||||||
|
if not self.is_logged():
|
||||||
|
raise BrowserIncorrectPassword()
|
||||||
39
modules/bnporc/enterprise/pages.py
Normal file
39
modules/bnporc/enterprise/pages.py
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# Copyright(C) 2013 Laurent Bachelier
|
||||||
|
#
|
||||||
|
# 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 weboob.tools.browser import BasePage
|
||||||
|
|
||||||
|
__all__ = ['LoginPage', 'AccountsPage']
|
||||||
|
|
||||||
|
|
||||||
|
class BEPage(BasePage):
|
||||||
|
def get_error(self):
|
||||||
|
for title in self.document.xpath('/html/head/title'):
|
||||||
|
if 'erreur' in title.text or 'error' in title.text:
|
||||||
|
return self.parser.select(self.document.getroot(),
|
||||||
|
'input[@name="titre_page"]', 1).value
|
||||||
|
|
||||||
|
|
||||||
|
class LoginPage(BEPage):
|
||||||
|
def login(self, username, password):
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
|
||||||
|
class AccountsPage(BEPage):
|
||||||
|
pass
|
||||||
Loading…
Add table
Add a link
Reference in a new issue