pax_global_header 0000666 0000000 0000000 00000000064 13514067645 0014525 g ustar 00root root 0000000 0000000 52 comment=d55ee1b5fb5ebdd456ab724438e5913e5a54d0c9
woob-d55ee1b5fb5ebdd456ab724438e5913e5a54d0c9-modules-bnppere/ 0000775 0000000 0000000 00000000000 13514067645 0022740 5 ustar 00root root 0000000 0000000 woob-d55ee1b5fb5ebdd456ab724438e5913e5a54d0c9-modules-bnppere/modules/ 0000775 0000000 0000000 00000000000 13514067645 0024410 5 ustar 00root root 0000000 0000000 woob-d55ee1b5fb5ebdd456ab724438e5913e5a54d0c9-modules-bnppere/modules/bnppere/ 0000775 0000000 0000000 00000000000 13514067645 0026043 5 ustar 00root root 0000000 0000000 woob-d55ee1b5fb5ebdd456ab724438e5913e5a54d0c9-modules-bnppere/modules/bnppere/__init__.py 0000664 0000000 0000000 00000001516 13514067645 0030157 0 ustar 00root root 0000000 0000000 # -*- coding: utf-8 -*-
# Copyright(C) 2016 Edouard Lambert
#
# This file is part of a weboob module.
#
# This weboob module is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This weboob module 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this weboob module. If not, see .
from .module import BnppereModule
__all__ = ['BnppereModule']
woob-d55ee1b5fb5ebdd456ab724438e5913e5a54d0c9-modules-bnppere/modules/bnppere/browser.py 0000664 0000000 0000000 00000006356 13514067645 0030112 0 ustar 00root root 0000000 0000000 # -*- coding: utf-8 -*-
# Copyright(C) 2016 Edouard Lambert
#
# This file is part of a weboob module.
#
# This weboob module is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This weboob module 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this weboob module. 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'
def get_profile(self):
raise NotImplementedError()
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, account):
raise NotImplementedError()
def iter_pocket(self, account):
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-d55ee1b5fb5ebdd456ab724438e5913e5a54d0c9-modules-bnppere/modules/bnppere/module.py 0000664 0000000 0000000 00000004335 13514067645 0027707 0 ustar 00root root 0000000 0000000 # -*- coding: utf-8 -*-
# Copyright(C) 2016 Edouard Lambert
#
# This file is part of a weboob module.
#
# This weboob module is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This weboob module 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this weboob module. 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 = 'LGPLv3+'
VERSION = '1.6'
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-d55ee1b5fb5ebdd456ab724438e5913e5a54d0c9-modules-bnppere/modules/bnppere/pages.py 0000664 0000000 0000000 00000010543 13514067645 0027517 0 ustar 00root root 0000000 0000000 # -*- coding: utf-8 -*-
# Copyright(C) 2018 Simon Rochwerg
#
# This file is part of a weboob module.
#
# This weboob module is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This weboob module 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this weboob module. 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, NumberFormatError
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'
def store(self, obj):
# This code enables indexing account_id when there
# are several accounts with the exact same id.
id = obj.id
n = 1
while id in self.objects:
n += 1
id = '%s-%s' % (obj.id, n)
obj.id = id
self.objects[obj.id] = obj
return obj
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_type = Account.TYPE_PERP
def obj_balance(self):
# The page can be randomly in french or english and
# the valuations can be "€12,345.67" or "12 345,67 €"
try:
return CleanDecimal.French('./td[6]')(self)
except NumberFormatError:
return CleanDecimal.US('./td[6]')(self)
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
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-d55ee1b5fb5ebdd456ab724438e5913e5a54d0c9-modules-bnppere/modules/bnppere/test.py 0000664 0000000 0000000 00000002023 13514067645 0027371 0 ustar 00root root 0000000 0000000 # -*- coding: utf-8 -*-
# Copyright(C) 2015 Christophe Lampin
#
# This file is part of a weboob module.
#
# This weboob module is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This weboob module 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this weboob module. 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))