pax_global_header 0000666 0000000 0000000 00000000064 13414430553 0014514 g ustar 00root root 0000000 0000000 52 comment=6e2147adbb0d685e8e740a246e0c7f31465f3511
woob-6e2147adbb0d685e8e740a246e0c7f31465f3511-modules-bnppere/ 0000775 0000000 0000000 00000000000 13414430553 0022415 5 ustar 00root root 0000000 0000000 woob-6e2147adbb0d685e8e740a246e0c7f31465f3511-modules-bnppere/modules/ 0000775 0000000 0000000 00000000000 13414430553 0024065 5 ustar 00root root 0000000 0000000 woob-6e2147adbb0d685e8e740a246e0c7f31465f3511-modules-bnppere/modules/bnppere/ 0000775 0000000 0000000 00000000000 13414430553 0025520 5 ustar 00root root 0000000 0000000 woob-6e2147adbb0d685e8e740a246e0c7f31465f3511-modules-bnppere/modules/bnppere/__init__.py 0000664 0000000 0000000 00000001441 13414430553 0027631 0 ustar 00root root 0000000 0000000 # -*- coding: utf-8 -*-
# Copyright(C) 2016 Edouard Lambert
#
# 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 .module import BnppereModule
__all__ = ['BnppereModule']
woob-6e2147adbb0d685e8e740a246e0c7f31465f3511-modules-bnppere/modules/bnppere/browser.py 0000664 0000000 0000000 00000006071 13414430553 0027561 0 ustar 00root root 0000000 0000000 # -*- coding: utf-8 -*-
# Copyright(C) 2016 Edouard Lambert
#
# 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 __future__ import unicode_literals
from weboob.browser import AbstractBrowser, LoginBrowser, URL, need_login
from weboob.exceptions import BrowserIncorrectPassword, BrowserUnavailable, ActionNeeded
from .pages import LoginPage, ProfilePage, ErrorPage, AccountPage, TermPage, UnexpectedPage, HistoryPage
class BnppereBrowser(AbstractBrowser):
PARENT = 's2e'
PARENT_ATTR = 'package.browser.BnppereBrowser'
class VisiogoBrowser(LoginBrowser):
BASEURL = 'https://visiogo.bnpparibas.com/'
login_page = URL(r'https://authentication.bnpparibas.com/en/Account/Login\?ReturnUrl=https://visiogo.bnpparibas.com/fr-FR', LoginPage)
error_page = URL(r'https://authentication.bnpparibas.com/en/account/login\?ReturnUrl=.+', ErrorPage)
error_page2 = URL(r'https://authentication.bnpparibas.com/Error\?Code=500', UnexpectedPage)
term_page = URL(r'/Home/TermsOfUseApproval', TermPage)
account_page = URL(r'/GlobalView/Synthesis', AccountPage)
profile_page = URL(r'/en/Profile/EditContactDetails', ProfilePage)
history_page = URL(r'en/Operation/History', HistoryPage)
def __init__(self, config=None, *args, **kwargs):
self.config = config
kwargs['username'] = self.config['login'].get()
kwargs['password'] = self.config['password'].get()
super(VisiogoBrowser, self).__init__(*args, **kwargs)
def do_login(self):
self.login_page.go()
self.page.login(self.username, self.password)
if self.term_page.is_here():
raise ActionNeeded()
if self.error_page.is_here() or self.error_page2.is_here():
alert = self.page.get_error()
if "account has not been activated" in alert:
raise ActionNeeded(alert)
elif "unexpected" in alert:
raise BrowserUnavailable(alert)
elif "password" in alert:
raise BrowserIncorrectPassword(alert)
else:
assert False
@need_login
def iter_accounts(self):
self.account_page.go()
return self.page.get_accounts()
def iter_investment(self, accounts):
raise NotImplementedError()
def get_profile(self):
self.profile_page.go()
return self.page.get_profile()
def iter_history(self, account):
self.history_page.stay_or_go()
return self.page.iter_history(account)
woob-6e2147adbb0d685e8e740a246e0c7f31465f3511-modules-bnppere/modules/bnppere/module.py 0000664 0000000 0000000 00000004260 13414430553 0027361 0 ustar 00root root 0000000 0000000 # -*- coding: utf-8 -*-
# Copyright(C) 2016 Edouard Lambert
#
# 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 weboob.tools.backend import AbstractModule, BackendConfig
from weboob.tools.value import ValueBackendPassword, Value
from weboob.capabilities.bank import CapBankWealth
from weboob.capabilities.profile import CapProfile
from .browser import BnppereBrowser, VisiogoBrowser
__all__ = ['BnppereModule']
class BnppereModule(AbstractModule, CapBankWealth, CapProfile):
NAME = 'bnppere'
DESCRIPTION = u'BNP Épargne Salariale'
MAINTAINER = u'Edouard Lambert'
EMAIL = 'elambert@budget-insight.com'
LICENSE = 'AGPLv3+'
VERSION = '1.4'
CONFIG = BackendConfig(
ValueBackendPassword('login', label='Identifiant', masked=False),
ValueBackendPassword('password', label='Code secret'),
Value('otp', label=u'Code de sécurité', default='', regexp='^(\d{6})$'),
Value('website', label='Espace Client', default='personeo',
choices={'personeo': 'PEE, PERCO (Personeo)', 'visiogo': 'PER Entreprises (Visiogo)'}))
PARENT = 's2e'
def create_default_browser(self):
b = {'personeo': BnppereBrowser, 'visiogo': VisiogoBrowser}
self.BROWSER = b[self.config['website'].get()]
return self.create_browser(self.config, weboob=self.weboob)
def iter_accounts(self):
return self.browser.iter_accounts()
def iter_history(self, account):
return self.browser.iter_history(account)
def get_profile(self):
return self.browser.get_profile()
woob-6e2147adbb0d685e8e740a246e0c7f31465f3511-modules-bnppere/modules/bnppere/pages.py 0000664 0000000 0000000 00000007532 13414430553 0027200 0 ustar 00root root 0000000 0000000 # -*- coding: utf-8 -*-
# Copyright(C) 2018 Simon Rochwerg
#
# 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 __future__ import unicode_literals
from weboob.browser.pages import HTMLPage, LoggedPage
from weboob.browser.elements import method, ItemElement, ListElement
from weboob.browser.filters.standard import CleanText, CleanDecimal, Format, Currency, Date
from weboob.capabilities.bank import Account, Transaction
from weboob.browser.filters.html import Attr
from weboob.capabilities.profile import Profile
class LoginPage(HTMLPage):
def login(self, login, password):
form = self.get_form('//form[@class="form-horizontal"]')
form['Login'] = login
form['Password'] = password
form.submit()
class ErrorPage(HTMLPage):
def get_error(self):
alert = CleanText('//td/div[@class="editorialContent"]|//div[has-class("blockMaintenance")]/table//p[contains(text(), "password")]')(self.doc)
if alert:
return alert
class ProfilePage(LoggedPage, HTMLPage):
@method
class get_profile(ItemElement):
klass = Profile
obj_name = CleanText('//*[@id="navAffiliationInfos"]/ul/li[1]')
obj_address = CleanText('//*[@id="1a"]/div[2]/div/div[1]/span')
obj_email = Attr('//*[@id="Email"]', 'value')
class TermPage(HTMLPage):
pass
class UnexpectedPage(HTMLPage):
def get_error(self):
alert = CleanText('//div[@class="blockMaintenance mainBlock"]/table//td/h3')(self.doc)
if alert:
return alert
class AccountPage(LoggedPage, HTMLPage):
@method
class get_accounts(ListElement):
item_xpath = '//div[@id="desktop-data-tables"]/table//tr'
class item(ItemElement):
klass = Account
def obj_id(self):
_id = CleanText('./td[1]')(self)
_id = ''.join(i for i in _id if i.isdigit())
return _id
def obj_label(self):
label = Format('%s', CleanText('./td[2]'))(self)
label = label.replace(" o ", " ")
return label
obj__login = CleanDecimal('./td[1]')
obj_currency = Currency('./td[6]')
obj__company = CleanText('./td[3]')
obj_balance = CleanDecimal('./td[6]', replace_dots=True)
obj_type = Account.TYPE_PERP
class HistoryPage(LoggedPage, HTMLPage):
@method
class iter_history(ListElement):
item_xpath = '//div[@class="accordion_container"]//div[@class="accordion_head-container"]'
class item(ItemElement):
klass = Transaction
def obj_id(self):
label = CleanText(Attr('./a[contains(@class, "accordion_collapse")]', "id"))(self)
label = ''.join(i for i in label if i.isdigit())
return label
obj_date = Date(CleanText('./div[contains(@class, "accordion_header")]/div[1]/p'))
obj_category = CleanText('./div[contains(@class, "accordion_header")]/div[2]/p[1]')
obj_label = CleanText('./div[contains(@class, "accordion_header")]/div[3]/p[1]')
obj_amount = CleanDecimal('./div[contains(@class, "accordion_header")]/div[6]')
obj__currency = Currency('./div[contains(@class, "accordion_header")]/div[6]')
woob-6e2147adbb0d685e8e740a246e0c7f31465f3511-modules-bnppere/modules/bnppere/test.py 0000664 0000000 0000000 00000001746 13414430553 0027061 0 ustar 00root root 0000000 0000000 # -*- coding: utf-8 -*-
# Copyright(C) 2015 Christophe Lampin
#
# 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 weboob.tools.test import BackendTest
class BnppereTest(BackendTest):
MODULE = 'bnppere'
def test_bank(self):
l = list(self.backend.iter_accounts())
if len(l) > 0:
a = l[0]
list(self.backend.iter_history(a))